Revision 694

Date:
2018/08/13 17:27:52
Author:
ahitrov
Revision Log:
Bug fixes

Files:

Legend:

 
Added
 
Removed
 
Modified
  • utf8/plugins/money/config.proto

     
    11 11 DREAMKAS_ID =
    12 12 DREAMKAS_SECRET = 123
    13 13 DREAMKAS_CURRENCY_CODE = RUB
    14 DREAMKAS_DEVICE_ID = NNNNN # ID кассового аппарата в системе Dreamkas
    14 15 DREAMKAS_TAX_MODE = DEFAULT # DEFAULT or SIMPLE or SIMPLE_WO or ENVD or AGRICULT or PATENT
    15 16 DREAMKAS_TAX_NDS = NDS_NO_TAX # NDS_NO_TAX or NDS_0 or NDS_10 or NDS_18 or NDS_20 or NDS_10_CALCULATED or NDS_18_CALCULATED
    16 17 DREAMKAS_TEST_MODE = 1 # 0 - для боевого режима
  • utf8/plugins/money/lib/money/Check.pm

     
    1 package money::Check;
    2
    3 use base "Contenido::Document";
    4 sub extra_properties
    5 {
    6 return (
    7 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус тестирования',
    8 'cases' => [
    9 [0, 'Реальный чек'],
    10 [1, 'Тестовый чек'],
    11 ],
    12 },
    13 )
    14 }
    15
    16 sub class_name
    17 {
    18 return 'Money: онлайн-чек';
    19 }
    20
    21 sub class_description
    22 {
    23 return 'Money: онлайн-чек';
    24 }
    25
    26 sub class_table
    27 {
    28 return 'money::SQL::ChecksTable';
    29 }
    30
    31 1;
  • utf8/plugins/money/lib/money/Init.pm

     
    12 12 # money::SQL::SomeTable
    13 13 # money::SomeClass
    14 14 Contenido::Init::load_classes(qw(
    15 money::SQL::MovementsTable
    16 money::Movement
    15 money::SQL::ChecksTable
    16 money::Check
    17 17
    18 18 money::MovementSection
    19 19
    20 20 money::Provider::Base
    21 money::Provider::Dreamkas
    21 22 ));
    22 23
    23 24 sub init {
  • utf8/plugins/money/lib/money/Movement.pm

     
    1 package money::Movement;
    2
    3 use base "Contenido::Document";
    4 sub extra_properties
    5 {
    6 return (
    7 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус тестирования',
    8 'cases' => [
    9 [0, 'Реальный чек'],
    10 [1, 'Тестовый чек'],
    11 ],
    12 },
    13 )
    14 }
    15
    16 sub class_name
    17 {
    18 return 'Money: онлайн-чек';
    19 }
    20
    21 sub class_description
    22 {
    23 return 'Money: онлайн-чек';
    24 }
    25
    26 sub class_table
    27 {
    28 return 'money::SQL::MovementsTable';
    29 }
    30
    31 1;
  • utf8/plugins/money/lib/money/MovementSection.pm

     
    19 19
    20 20 sub class_description
    21 21 {
    22 return 'Money: Секция транзакций';чеков
    22 return 'Money: Секция чеков';
    23 23 }
    24 24
    25 25 1;
  • utf8/plugins/money/lib/money/Provider/Dreamkas.pm

     
    74 74
    75 75 $self->{currency} = $state->{money}{$prefix."_currency_code"};
    76 76
    77 $self->{$base_url} = 'https://'. ($self->{test_mode} ? 'private-anon-f6c2f7b545-kabinet.apiary-mock.com' : 'kabinet.dreamkas.ru').'/api';
    77 $self->{base_url} = 'https://'. ($self->{test_mode} ? 'private-anon-f6c2f7b545-kabinet.apiary-mock.com' : 'kabinet.dreamkas.ru').'/api';
    78 78 $self->{result} = {};
    79 79
    80 80 bless $self, $class;
     
    189 189
    190 190 my $MM;
    191 191 if ( exists $opts->{order} ) {
    192 $MM = $self->_GetLastMoneyMovement( $opts->{order}->id );
    192 $MM = $self->_GetLastMoneyCheck( $opts->{order}->id );
    193 193 }
    194 194 if ( ref $MM && $MM->session_id && $MM->name eq $opts->{type} ) {
    195 195 $self->{result}{money_movement} = $MM;
    196 196 return $self;
    197 197 }
    198 198 unless ( $MM ) {
    199 $MM = money::Movement->new( $keeper );
    199 $MM = money::Check->new( $keeper );
    200 200 $MM->name( $opts->{type} );
    201 201 $MM->provider( $self->{prefix} );
    202 202 $MM->status( $self->{test_mode} );
     
    220 220 foreach my $bi ( @{$opts->{basket}} ) {
    221 221 my $item = $bi->{item};
    222 222 next unless ref $item;
    223 my $price = int($bi->{item}->price * 100)
    223 my $price = int($bi->{item}->price * 100);
    224 224 my $pos = {
    225 225 name => $bi->name,
    226 226 type => 'COUNTABLE',
     
    253 253 my $attributes = {};
    254 254 if ( exists $opts->{email} && $opts->{email} ) {
    255 255 if ( ref $opts->{email} ) {
    256 $arrtibutes->{email} = $opts->{email}->name;
    256 $attributes->{email} = $opts->{email}->name;
    257 257 } else {
    258 $arrtibutes->{email} = $opts->{email};
    258 $attributes->{email} = $opts->{email};
    259 259 }
    260 260 }
    261 261 if ( exists $opts->{phone} && $opts->{phone} ) {
    262 262 if ( ref $opts->{phone} ) {
    263 $arrtibutes->{phone} = $opts->{phone}->name;
    263 $attributes->{phone} = $opts->{phone}->name;
    264 264 } else {
    265 $arrtibutes->{phone} = $opts->{phone};
    265 $attributes->{phone} = $opts->{phone};
    266 266 }
    267 267 }
    268 268 $data->{attributes} = $attributes;
     
    286 286 $data->{payments}{type} = 'CASH';
    287 287 }
    288 288
    289 my $api_url = '/api/receipts';
    289 my $api_url = 'receipts';
    290 290
    291 291 $self->_MakeRequest( $api_url, 'post', $data );
    292 292 if ( $self->{result}{code} == 202 ) {
     
    346 346 } elsif ( exists $opts->{money_movement} ) {
    347 347 $MM = $opts->{money_movement};
    348 348 } elsif ( $opts->{operation_id} ) {
    349 ($MM) = $self->_GetMMByOperationId( $opts->{operation_id} );
    349 ($MM) = $self->_GetCheckByOperationId( $opts->{operation_id} );
    350 350 }
    351 351 unless ( ref $MM ) {
    352 352 $self->{result}{error} = 'Не найден объект "движение денежных средств". Проверьте входные параметры';
    353 353 return $self;
    354 354 }
    355 355
    356 my $api_url = '/api/operations/'.$MM->session_id;
    356 my $api_url = 'operations/'.$MM->session_id;
    357 357
    358 358 $self->_MakeRequest( $api_url, 'get' );
    359 359 if ( $self->{result}{code} == 200 ) {
     
    388 388 $body = encode_json( $body );
    389 389 }
    390 390
    391 my $req = URI->new( $self->{host}.($url =~ /^\// ? '' : '/').$url );
    391 my $req = URI->new( $self->{base_url}.($url =~ /^\// ? '' : '/').$url );
    392 392 my $res;
    393 393 if ( $type eq 'post' ) {
    394 394 $res = $ua->post( $req, Content => $body );
     
    401 401 code => $res->code,
    402 402 status => $res->status_line,
    403 403 content => JSON::XS->new->decode( $res->decoded_content ),
    404 }
    404 };
    405 405 return $self;
    406 406 }
    407 407
    408 sub _GetLastMoneyMovement {
    408 sub _GetLastMoneyCheck {
    409 409 my $self = shift;
    410 410 my $order_id = shift;
    411 411 my ($mm) = $keeper->get_documents(
    412 class => 'money::Movement',
    412 class => 'money::Check',
    413 413 limit => 1,
    414 order_id => $order_id
    414 provider => $self->{prefix},
    415 order_id => $order_id,
    415 416 order_by => 'id desc',
    416 417 );
    417 418 return $mm;
    418 419 }
    419 420
    420 sub _GetMMByOperationId {
    421 sub _GetCheckByOperationId {
    421 422 my $self = shift;
    422 423 my $op_id = shift;
    423 424 my ($mm) = $keeper->get_documents(
    424 class => 'money::Movement',
    425 class => 'money::Check',
    425 426 limit => 1,
    427 provider => $self->{prefix},
    426 428 session_id => $op_id,
    427 429 );
    428 430 return $mm;
  • utf8/plugins/money/lib/money/SQL/ChecksTable.pm

     
    1 package money::SQL::ChecksTable;
    2
    3 use base 'SQL::DocumentTable';
    4
    5 sub db_table
    6 {
    7 return 'money_movements';
    8 }
    9
    10 sub db_id_sequence {
    11 return 'money_movements_id_seq';
    12 }
    13
    14 sub available_filters {
    15 my @available_filters = qw(
    16
    17 _class_filter
    18 _status_filter
    19 _in_id_filter
    20 _id_filter
    21 _name_filter
    22 _class_excludes_filter
    23 _sfilter_filter
    24 _excludes_filter
    25 _datetime_filter
    26 _date_equal_filter
    27 _date_filter
    28 _previous_days_filter
    29
    30 _provider_filter
    31 _session_id_filter
    32 _order_id_filter
    33 _success_filter
    34 _name_exact_filter
    35 );
    36
    37 return \@available_filters;
    38 }
    39
    40 # ----------------------------------------------------------------------------
    41 # Свойства храним в массивах, потому что порядок важен!
    42 # Это общие свойства - одинаковые для всех документов.
    43 #
    44 # attr - обязательный параметр, название атрибута;
    45 # type - тип аттрибута, требуется для отображдения;
    46 # rusname - русское название, опять же требуется для отображения;
    47 # hidden - равен 1, когда
    48 # readonly - инициализации при записи только без изменения в дальнейшем
    49 # db_field - поле в таблице
    50 # default - значение по умолчанию (поле всегда имеет это значение)
    51 # ----------------------------------------------------------------------------
    52 sub required_properties
    53 {
    54 my $self = shift;
    55
    56 my @parent_properties = grep { $_->{attr} ne 'sections' } $self->SUPER::required_properties;
    57 return (
    58 @parent_properties,
    59 {
    60 'attr' => 'provider',
    61 'type' => 'string',
    62 'rusname' => 'Провайдер',
    63 'db_field' => 'provider',
    64 'db_type' => 'text',
    65 },
    66 {
    67 'attr' => 'session_id',
    68 'type' => 'string',
    69 'rusname' => 'Ключ сессии',
    70 'db_field' => 'session_id',
    71 'db_type' => 'text',
    72 },
    73 { # ID заказа
    74 'attr' => 'order_id',
    75 'type' => 'integer',
    76 'rusname' => 'ID заказа',
    77 'db_field' => 'order_id',
    78 'db_type' => 'integer',
    79 'db_opts' => "not null",
    80 },
    81 {
    82 'attr' => 'currency_code',
    83 'type' => 'string',
    84 'rusname' => 'ID валюты',
    85 'db_field' => 'currency_code',
    86 'db_type' => 'varchar(4)',
    87 },
    88 {
    89 'attr' => 'sum',
    90 'type' => 'string',
    91 'rusname' => 'Сумма чека',
    92 'db_field' => 'sum',
    93 'db_type' => 'float',
    94 },
    95 { # Результат транзакции
    96 'attr' => 'success',
    97 'type' => 'checkbox',
    98 'rusname' => 'Транзакция прошла успешно',
    99 'db_field' => 'success',
    100 'db_type' => 'smallint',
    101 'db_opts' => "default 0",
    102 },
    103 );
    104 }
    105
    106
    107 ########### FILTERS DESCRIPTION ###############################################################################
    108 sub _order_id_filter {
    109 my ($self,%opts)=@_;
    110 return undef unless ( exists $opts{order_id} );
    111 return &SQL::Common::_generic_int_filter('d.order_id', $opts{order_id});
    112 }
    113
    114 sub _success_filter {
    115 my ($self,%opts)=@_;
    116 return undef unless ( exists $opts{success} );
    117 return &SQL::Common::_generic_int_filter('d.success', $opts{success});
    118 }
    119
    120 sub _provider_filter {
    121 my ($self,%opts)=@_;
    122 return undef unless ( exists $opts{provider} );
    123 return &SQL::Common::_generic_text_filter('d.provider', $opts{provider});
    124 }
    125
    126 sub _session_id_filter {
    127 my ($self,%opts)=@_;
    128 return undef unless ( exists $opts{session_id} );
    129 return &SQL::Common::_generic_int_filter('d.session_id', $opts{session_id});
    130 }
    131
    132 sub _name_exact_filter {
    133 my ($self,%opts)=@_;
    134 return undef unless ( exists $opts{name_exact} );
    135 return &SQL::Common::_generic_text_filter('d.name', $opts{name_exact});
    136 }
    137
    138 1;
  • utf8/plugins/money/lib/money/SQL/MovementsTable.pm

     
    1 package money::SQL::MovementsTable;
    2
    3 use base 'SQL::DocumentTable';
    4
    5 sub db_table
    6 {
    7 return 'money_movements';
    8 }
    9
    10 sub db_id_sequence {
    11 return 'money_movements_id_seq';
    12 }
    13
    14 sub available_filters {
    15 my @available_filters = qw(
    16
    17 _class_filter
    18 _status_filter
    19 _in_id_filter
    20 _id_filter
    21 _name_filter
    22 _class_excludes_filter
    23 _sfilter_filter
    24 _excludes_filter
    25 _datetime_filter
    26 _date_equal_filter
    27 _date_filter
    28 _previous_days_filter
    29
    30 _provider_filter
    31 _session_id_filter
    32 _order_id_filter
    33 _success_filter
    34 _name_exact_filter
    35 );
    36
    37 return \@available_filters;
    38 }
    39
    40 # ----------------------------------------------------------------------------
    41 # Свойства храним в массивах, потому что порядок важен!
    42 # Это общие свойства - одинаковые для всех документов.
    43 #
    44 # attr - обязательный параметр, название атрибута;
    45 # type - тип аттрибута, требуется для отображдения;
    46 # rusname - русское название, опять же требуется для отображения;
    47 # hidden - равен 1, когда
    48 # readonly - инициализации при записи только без изменения в дальнейшем
    49 # db_field - поле в таблице
    50 # default - значение по умолчанию (поле всегда имеет это значение)
    51 # ----------------------------------------------------------------------------
    52 sub required_properties
    53 {
    54 my $self = shift;
    55
    56 my @parent_properties = grep { $_->{attr} ne 'sections' } $self->SUPER::required_properties;
    57 return (
    58 @parent_properties,
    59 {
    60 'attr' => 'provider',
    61 'type' => 'string',
    62 'rusname' => 'Провайдер',
    63 'db_field' => 'provider',
    64 'db_type' => 'text',
    65 },
    66 {
    67 'attr' => 'session_id',
    68 'type' => 'string',
    69 'rusname' => 'Ключ сессии',
    70 'db_field' => 'session_id',
    71 'db_type' => 'text',
    72 },
    73 { # ID заказа
    74 'attr' => 'order_id',
    75 'type' => 'integer',
    76 'rusname' => 'ID заказа',
    77 'db_field' => 'order_id',
    78 'db_type' => 'integer',
    79 'db_opts' => "not null",
    80 },
    81 {
    82 'attr' => 'currency_code',
    83 'type' => 'string',
    84 'rusname' => 'ID валюты',
    85 'db_field' => 'currency_code',
    86 'db_type' => 'varchar(4)',
    87 },
    88 {
    89 'attr' => 'sum',
    90 'type' => 'string',
    91 'rusname' => 'Сумма чека',
    92 'db_field' => 'sum',
    93 'db_type' => 'float',
    94 },
    95 { # Результат транзакции
    96 'attr' => 'success',
    97 'type' => 'checkbox',
    98 'rusname' => 'Транзакция прошла успешно',
    99 'db_field' => 'success',
    100 'db_type' => 'smallint',
    101 'db_opts' => "default 0",
    102 },
    103 );
    104 }
    105
    106
    107 ########### FILTERS DESCRIPTION ###############################################################################
    108 sub _order_id_filter {
    109 my ($self,%opts)=@_;
    110 return undef unless ( exists $opts{order_id} );
    111 return &SQL::Common::_generic_int_filter('d.order_id', $opts{order_id});
    112 }
    113
    114 sub _success_filter {
    115 my ($self,%opts)=@_;
    116 return undef unless ( exists $opts{success} );
    117 return &SQL::Common::_generic_int_filter('d.success', $opts{success});
    118 }
    119
    120 sub _provider_filter {
    121 my ($self,%opts)=@_;
    122 return undef unless ( exists $opts{provider} );
    123 return &SQL::Common::_generic_text_filter('d.provider', $opts{provider});
    124 }
    125
    126 sub _session_id_filter {
    127 my ($self,%opts)=@_;
    128 return undef unless ( exists $opts{session_id} );
    129 return &SQL::Common::_generic_int_filter('d.session_id', $opts{session_id});
    130 }
    131
    132 sub _name_exact_filter {
    133 my ($self,%opts)=@_;
    134 return undef unless ( exists $opts{name_exact} );
    135 return &SQL::Common::_generic_text_filter('d.name', $opts{name_exact});
    136 }
    137
    138 1;
  • utf8/plugins/money/sql/TOAST/money_checks.sql

     
    1 create sequence money_checks_id_seq;
    2 select setval('money_checks_id_seq', 1, true);
    3
    4 create table money_checks
    5 (
    6 id integer not null primary key default nextval('public.documents_id_seq'::text),
    7 class text not null,
    8 ctime timestamp not null default now(),
    9 mtime timestamp not null default now(),
    10 dtime timestamp not null default now(),
    11 status smallint not null default 0,
    12 provider text,
    13 session_id text,
    14 name text,
    15 order_id integer not null,
    16 currency_code varchar(4),
    17 sum float,
    18 success smallint default 0,
    19 data text
    20 );
    21 CREATE INDEX money_checks_sessions ON money_checks USING btree (provider, session_id) WHERE session_id is not null;
    22 CREATE INDEX money_checks_orders ON money_checks USING btree (order_id);
  • utf8/plugins/money/sql/TOAST/money_movement.sql

     
    1 create sequence money_movements_id_seq;
    2 select setval('money_movements_id_seq', 1, true);
    3
    4 create table money_movements
    5 (
    6 id integer not null primary key default nextval('public.documents_id_seq'::text),
    7 class text not null,
    8 ctime timestamp not null default now(),
    9 mtime timestamp not null default now(),
    10 dtime timestamp not null default now(),
    11 status smallint not null default 0,
    12 provider text,
    13 session_id text,
    14 name text,
    15 order_id integer not null,
    16 currency_code varchar(4),
    17 sum float,
    18 success smallint default 0,
    19 data text
    20 );
    21 CREATE INDEX money_movements_sessions ON money_movements USING btree (provider, session_id) WHERE session_id is not null;
    22 CREATE INDEX money_movements_orders ON money_movements USING btree (order_id);

Небольшая справка по веткам

cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.

koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.

utf8 – актуальная ветка, заточенная под UTF-8.

Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.