Revision 563
Date:
2016/04/12 12:53:34
Author:
ahitrov
Revision Log:
Payment plugin contenido interface. Order finder and order actions
Files:
Legend:
Added
Removed
Modified
utf8/plugins/payments/comps/contenido/payments/ajax/__json.html
1
<% $json %>
2
<%once>
3
4
use JSON::XS;
5
6
</%once>
7
<%args>
8
9
$id => undef
10
11
</%args>
12
<%init>
13
14
my %result;
15
16
my $json = encode_json \%result;
17
18
</%init>
utf8/plugins/payments/comps/contenido/payments/ajax/order_info.html
1
<% $json %>
2
<%once>
3
4
use JSON::XS;
5
use utf8;
6
7
</%once>
8
<%args>
9
10
$id => undef
11
12
</%args>
13
<%init>
14
15
my %result;
16
if ( $id && $id =~ /^\d+$/ ) {
17
my $order = $keeper->{payments}->get_order( $id );
18
if ( ref $order ) {
19
$result{brief} = Encode::decode('utf-8', $m->scomp('/contenido/payments/components/block_order_brief.msn', order => $order));
20
$result{actions} = Encode::decode('utf-8', $m->scomp('/contenido/payments/components/order_actions.msn', order_id => $order->id));
21
}
22
} else {
23
$result{error} = 'Не указан или неверно указан идентификатор заказа';
24
}
25
26
my $json = encode_json \%result;
27
28
</%init>
utf8/plugins/payments/comps/contenido/payments/components/block_order_brief.msn
1
<div style="border:1px solid gray; padding:5px; margin:5px; color:gray; font-size:90%;">
2
% if ( ref $order ) {
3
<b class="prompt">Номер:</b> <% $order->id %><br>
4
<b class="prompt">Пользователь:</b> <% $order->name %><br>
5
<b class="prompt">Статус:</b> <% exists $status_order{$order->status} ? $status_order{$order->status} : 'неизвестный' %><br>
6
<b class="prompt">Оплата:</b> <% exists $status_payment{$order->payment} ? $status_payment{$order->payment} : 'неизвестно' %><br>
7
% if ( exists $order->{list} && ref $order->{list} eq 'ARRAY' && @{$order->{list}} ) {
8
% my $i = 1;
9
<table width="100%" border="0" cellpadding="3" cellspacing="0" class="tlistdocs">
10
<tr>
11
<th align="center" width="1%">#</th>
12
<th align="center" width="97%">Позиция</th>
13
<th align="center" width="1%">К-во</th>
14
<th align="center" width="1%">Сумма</th>
15
</tr>
16
% foreach my $doc ( @{$order->{list}} ) {
17
<tr align="center">
18
<td nowrap><% $i++ %></td>
19
<td align="left"><% $doc->name %></td>
20
<td nowrap><% $doc->number %></td>
21
<td nowrap><% sprintf("%.2f", $doc->price * $doc->number) %></td>
22
</tr>
23
% }
24
</table>
25
% }
26
<b class="prompt">Всего:</b> <% $order->num %><br>
27
<b class="prompt">Итог:</b> <% sprintf("%.2f", $order->sum_total) %><br>
28
% } else {
29
% if ( grep { $_ eq 'webshop' } split /\s+/, $state->plugins ) {
30
<p class="err">Заказ с таким id в базе не найден.</p>
31
% } else {
32
<p class="rem">Плагин веб-магазина не подключен. Поиск параметров заказа невозможен.</p>
33
% }
34
% }
35
</div>
36
<%args>
37
38
$order => undef
39
40
</%args>
41
<%init>
42
43
my (%status_order, %status_payment);
44
if ( ref $order ) {
45
my ($statord) = grep { $_->{attr} eq 'status' } $order->structure;
46
my ($statpay) = grep { $_->{attr} eq 'payment' } $order->structure;
47
%status_order = map { $_->[0] => $_->[1] } @{$statord->{cases}};
48
%status_payment = map { $_->[0] => $_->[1] } @{$statpay->{cases}};
49
}
50
51
</%init>
utf8/plugins/payments/comps/contenido/payments/components/block_transaction.msn
1
<div style="border:1px solid gray; margin:10px 0; padding:5px; background:<% $bg_color %>;">
2
<div style="width:200px; float:right;"><% $transaction->status ? 'Рабочая транзакция' : 'Тестовая транзакция' %> (<% $transaction->provider %>)</div>
3
<% $dt->dmy('.').' '.$dt->hms %><br>
4
<h4><% $transaction->name %></h4>
5
<p>Сумма в валюте транзакции: <b><% sprintf("%.2f", $transaction->sum ) %> <% $transaction->currency_code %></b></p>
6
</div>
7
<%once>
8
</%once>
9
<%args>
10
11
$transaction => undef
12
$operations => []
13
14
</%args>
15
<%init>
16
17
my $bg_color = $transaction->status ? $transaction->success ? '#e8ffe8' : '#ffe8e8' : '#e8e8e8';
18
my $dt = Contenido::DateTime->new( postgres => $transaction->mtime );
19
20
</%init>
utf8/plugins/payments/comps/contenido/payments/components/block_transaction_payture.msn
1
<div style="border:1px solid gray; margin:10px 0; padding:5px; background:<% $bg_color %>;">
2
<div style="width:200px; float:right;"><% $transaction->status ? 'Рабочая транзакция' : 'Тестовая транзакция' %> (PayTure)</div>
3
<% $dt->dmy('.').' '.$dt->hms %><br>
4
% if ( exists $TYPE{$transaction->name} ) {
5
<h4><% $TYPE{$transaction->name} %></h4>
6
% } else {
7
<h4><% $transaction->name %></h4>
8
% }
9
<p>
10
Статус операции: <% $transaction->success ? '<b style="color:green;">Успех</b>' : '<b style="color:red;">Неудача</b>' %><br>
11
Сумма в валюте транзакции: <b><% sprintf("%.2f", $transaction->sum / 100) %> <% $transaction->currency_code %></b><br>
12
</p>
13
</div>
14
<%once>
15
16
my %TYPE = (
17
'Init' => 'Инициализация',
18
'Charged' => 'Списание денежных средств',
19
# '' => '',
20
);
21
22
</%once>
23
<%args>
24
25
$transaction => undef
26
27
</%args>
28
<%init>
29
30
my $bg_color = $transaction->status ? $transaction->success ? '#e8ffe8' : '#ffe8e8' : '#e8e8e8';
31
my $dt = Contenido::DateTime->new( postgres => $transaction->mtime );
32
33
</%init>
utf8/plugins/payments/comps/contenido/payments/components/form_order_finder.msn
1
<script type="text/javascript">
2
<!--
3
$(document).ready(function(){
4
$('#search-order-form').on('submit', function( ev ){
5
ev.preventDefault();
6
var order_id = $(this).find('input[name=order_id]').val();
7
if ( order_id ) {
8
$.ajax({
9
'url' : '/contenido/payments/ajax/order_info.html',
10
'data' : { 'id' : order_id },
11
'dataType' : 'json',
12
'success' : function( data ){
13
if ( data.brief ) {
14
$('#order-info').html( data.brief );
15
}
16
if ( data.actions ) {
17
$('#order-actions').html( data.actions );
18
}
19
}
20
});
21
}
22
});
23
});
24
//-->
25
</script>
26
<style>
27
#form-order-finder b.prompt { display:inline-block; width:120px; }
28
</style>
29
<fieldset id="form-order-finder">
30
<legend>Поиск по номеру заказа</legend>
31
<form id="search-order-form" name="search_order" action="/contenido/payments/" method="GET" target="select">
32
<table width="100%" border="0" cellpadding="0" cellspacing="6" class="tform">
33
<tr><td width="98%"><input type="text" name="order_id" value="<% $order_id %>" style="width:97%;" placeholder="Введите идентификатор заказа"></td>
34
<td width="2%" nowrap>
35
<input type="submit" value="Искать" class="btn">
36
</td></tr>
37
</table>
38
</form>
39
<div id="order-info">
40
% if ( $order_id ) {
41
<& /contenido/payments/components/block_order_brief.msn, order => $order &>
42
% }
43
</div>
44
</fieldset>
45
<%args>
46
47
$order_id => undef
48
49
</%args>
50
<%init>
51
52
my $order = $keeper->{payments}->get_order( $order_id );
53
54
</%init>
utf8/plugins/payments/comps/contenido/payments/components/order_actions.msn
1
<fieldset>
2
<legend>Движения по заказу</legend>
3
% if ( @operations || @transactions ) {
4
% if ( @operations ) {
5
<h2>Операции</h2>
6
<table width="100%" border="0" cellpadding="4" cellspacing="0" class="tlistdocs">
7
<tr bgcolor="#efefef">
8
<th>ID заказа</th>
9
<th>Дата/время</th>
10
<th>Результат</th>
11
<th>Менеджер</th>
12
</tr>
13
% foreach my $op ( @operations ) {
14
% my $dt = Contenido::DateTime->new( postgres => $op->ctime );
15
% my $user = $op->uuid ? $keeper->get_user_by_id( $op->uuid ) : undef;
16
<tr>
17
<td><% $op->id %></td>
18
<td><% $dt->ymd('-').' '.$dt->hms %></td>
19
<td><% $opnames{$op->name} %></td>
20
<td>
21
% if ( ref $user ) {
22
% $m->out($user->name);
23
% } elsif ( $op->uuid ) {
24
Неопознанный (id=<% $op->uuid %>)
25
% }
26
</td>
27
</tr>
28
% }
29
</table>
30
<p class="rem">Операция - действие пользователя или менеджера по отношению к заказу.</p>
31
% }
32
% if ( @transactions ) {
33
<h2>Транзакции</h2>
34
% foreach my $tr ( @transactions ) {
35
% if ( $m->comp_exists( "/contenido/payments/components/block_transaction_".$tr->provider.".msn" ) ) {
36
% $m->comp( "/contenido/payments/components/block_transaction_".$tr->provider.".msn", transaction => $tr );
37
% } else {
38
% $m->comp( "/contenido/payments/components/block_transaction.msn", transaction => $tr );
39
% }
40
% }
41
<p class="rem">Транзакция - результат взаимодействия платежной системы и веб-магазина по отношению к заказу.</p>
42
% }
43
% } elsif ( $order_id ) {
44
<p class="rem">По данному номеру заказа ничего не найдено.</p>
45
% }
46
</fieldset>
47
<%once>
48
49
50
51
</%once>
52
<%args>
53
54
$order_id => undef
55
56
</%args>
57
<%init>
58
59
my ( @operations, @transactions );
60
61
if ( $order_id && $order_id =~ /^\d+$/ ) {
62
@operations = $keeper->get_documents(
63
class => 'payments::Operation',
64
order_id => $order_id,
65
order_by => 'ctime',
66
);
67
@transactions = $keeper->get_documents(
68
class => 'payments::Transaction',
69
order_id => $order_id,
70
order_by => 'ctime',
71
);
72
}
73
my ($prop) = grep { $_->{attr} eq 'name' } payments::Operation->new->structure;
74
my %opnames = map { $_->[0] => $_->[1] } @{$prop->{cases}};
75
76
</%init>
utf8/plugins/payments/comps/contenido/payments/index.html
1
1
<& "/contenido/components/header.msn" &>
2
2
<& "/contenido/components/naviline.msn" &>
3
3
4
<p>PLugin [payments]</p>
4
<script type="text/javascript">
5
<!--
6
var nOrderId = <% $order_id || 0 %>;
5
7
8
//-->
9
</script>
10
11
<table width="100%" cellspacing="0" cellpadding="0" border="0">
12
<tr valign="top">
13
<td width="35%">
14
<& /contenido/payments/components/form_order_finder.msn, order_id => $order_id &>
15
</td>
16
<td width="2%" nowrap> </td>
17
<td width="63%">
18
<div id="order-actions">
19
% if ( $order_id ) {
20
<& /contenido/payments/components/order_actions.msn, order_id => $order_id &>
21
% }
22
</div>
23
</td>
24
</tr>
25
</table>
26
6
27
</body>
7
28
</html>
29
<%args>
30
31
$order_id => undef
32
33
</%args>
34
<%init>
35
36
$order_id = undef unless $order_id && $order_id =~ /^\d+$/;
37
38
</%init>
utf8/plugins/payments/comps/www/payment.backend/payture_pay.html
43
43
$transaction->success( $Success eq 'True' ? 1 : 0 );
44
44
$transaction->store;
45
45
46
if ( $keeper->can('_payture_handler') ) {
46
if ( $transaction->success && $keeper->can('_payture_handler') ) {
47
47
$keeper->_payture_handler( $transaction );
48
48
}
49
49
}
utf8/plugins/payments/lib/payments/Keeper.pm
49
49
return undef;
50
50
}
51
51
52
sub get_order {
53
my $self = shift;
54
my $order_id = shift;
55
return undef unless $order_id;
52
56
57
if ( grep { $_ eq 'webshop' } split(/\s+/, $state->plugins) ) {
58
return $keeper->{webshop}->get_orders( id => $order_id, list => 1 );
59
}
60
}
61
53
62
1;
utf8/plugins/payments/lib/payments/Operation.pm
6
6
return (
7
7
{ 'attr' => 'name', 'type' => 'status', 'rusname' => 'Тип операции',
8
8
'cases' => [
9
['create', 'Заказ создан'],
10
['suspend', 'Заказ заморожен'],
11
['reform', 'Заказ изменен'],
12
['append', 'Доплата по заказу'],
13
['cancel', 'Заказ отменен'],
9
['create', 'создан'],
10
['suspend', 'заморожен'],
11
['reform', 'изменен'],
12
['append', 'доплата'],
13
['cancel', 'отменен'],
14
['close', 'закрыт'],
14
15
],
15
16
},
16
17
)
utf8/plugins/payments/lib/payments/SQL/OperationsTable.pm
58
58
'db_type' => 'integer',
59
59
'db_opts' => "default 0",
60
60
},
61
{
62
'attr' => 'uuid',
63
'type' => 'integer',
64
'rusname' => 'ID менеджера',
65
'db_field' => 'uuid',
66
'db_type' => 'integer',
67
},
61
68
{ # ID заказа
62
69
'attr' => 'order_id',
63
70
'type' => 'integer',
utf8/plugins/payments/lib/payments/State.pm.proto
12
12
bless $self, $class;
13
13
14
14
# configured
15
$self->{debug} = (lc('') eq 'yes');
16
$self->{project} = '';
15
$self->{project} = '@PROJECT@';
16
$self->{debug} = (lc('@DEBUG@') eq 'yes');
17
$self->{contenido_notab} = 0;
18
$self->{tab_name} = 'Онлайн-оплата';
19
$self->{project_name} = '@PROJECT_NAME@';
20
$self->{default_expire} = '@DEFAULT_EXPIRE@' || 300;
21
$self->{default_object_expire} = '@DEFAULT_OBJECT_EXPIRE@' || 600;
17
22
18
23
# зашитая конфигурация плагина
19
24
$self->{db_type} = 'none'; ### For REAL database use 'remote'
…
…
27
32
$self->{cascade} = 1;
28
33
$self->{db_prepare} = 0;
29
34
30
$self->{memcached_enable} = lc( '' ) eq 'yes' ? 1 : 0;
31
$self->{memcached_enable_compress} = 1;
32
$self->{memcached_backend} = '';
33
$self->{memcached_servers} = [qw()];
34
$self->{memcached_busy_lock} = 60;
35
$self->{memcached_delayed} = lc('') eq 'yes' ? 1 : 0;
35
$self->{memcached_enable} = lc( '@MEMCACHED_ENABLE@' ) eq 'yes' ? 1 : 0;
36
$self->{memcached_backend} = '@MEMCACHED_BACKEND@';
37
$self->{memcached_select_timeout} = '@MEMCACHED_SELECT_TIMEOUT@' || 0.2;
38
$self->{memcached_servers} = [qw(@MEMCACHED_SERVERS@)];
39
$self->{memcached_enable_compress} = lc( '@MEMCACHED_ENABLE_COMPRESS@' ) eq 'yes' ? 1 : 0;
40
$self->{memcached_delayed} = lc('@MEMCACHED_DELAYED@') eq 'yes' ? 1 : 0;
41
$self->{memcached_set_mode} = lc('@MEMCACHED_SET_MODE@') eq 'add' ? 'add' : 'set';
42
$self->{memcached_busy_lock} = 60;
43
$self->{memcached_namespace} = lc( $self->{'project'} ).'|plugin_payments|';
36
44
37
45
$self->{serialize_with} = 'json'; ### or 'dumper'
38
46
…
…
92
100
$self->{attributes}->{$_} = 'SCALAR' for qw(
93
101
debug
94
102
project
103
tab_name
95
104
96
105
db_type
97
106
db_keepalive
…
…
106
115
db_client_encoding
107
116
108
117
memcached_enable
118
memcached_servers
119
memcached_select_timeout
120
memcached_backend
109
121
memcached_enable_compress
110
memcached_backend
111
memcached_servers
122
memcached_set_mode
123
memcached_object_expire
112
124
memcached_busy_lock
113
125
memcached_delayed
126
memcached_namespace
114
127
115
128
binary_directory
116
129
data_directory
utf8/plugins/payments/sql/TOAST/operations.563.sql
1
alter table payments_operations add column uuid integer;
2
CREATE INDEX payments_operations_uuid ON payments_operations USING btree (uuid) where uuid is not null;
utf8/plugins/payments/sql/TOAST/operations.sql
8
8
name text,
9
9
order_id integer not null,
10
10
uid integer not null,
11
uuid integer,
11
12
sum float,
12
13
data text
13
14
);
Небольшая справка по веткам
cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.
koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.
utf8 – актуальная ветка, заточенная под UTF-8.
Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.