Revision 425

Date:
2014/03/06 23:28:32
Author:
ahitrov
Revision Log:
Скидки
Files:

Legend:

 
Added
 
Removed
 
Modified
  • utf8/plugins/webshop/comps/contenido/webshop/components/block_coupons.msn

     
    34 34 <%init>
    35 35
    36 36 my $now = Contenido::DateTime->new;
    37 my $sql = $keeper->SQL->prepare( 'select status, count(id) as cnt from webshop_coupons where ? <= etime group by status' );
    37 my $sql = $keeper->SQL->prepare( "select status, count(id) as cnt from webshop_coupons where class = 'webshop::Coupon' and ? <= etime group by status" );
    38 38 $sql->execute( $now->ymd('-').' '.$now->hms );
    39 39
    40 40 my %stats;
  • utf8/plugins/webshop/comps/contenido/webshop/components/block_discounts.msn

     
    1 <fieldset>
    2 <legend>Скидки</legend>
    3
    4 <table width="100%" border="0" cellpadding="3" cellspacing="0" class="tlistdocs">
    5 <tr class="<% $status == 1 ? 'inverted' : '' %>">
    6 <td><a href="/contenido/webshop/discounts.html">Активные:</a></td>
    7 <td><b><% $stats{1} || 0 %></b></td></tr>
    8 <tr class="<% defined $status && $status == 0 ? 'inverted' : '' %>">
    9 <td><a href="/contenido/webshop/discounts.html?cst=0" style="<% defined $status && $status == 0 ? '' : 'color:gray' %>">Неактивные:</a></td>
    10 <td><b><% $stats{0} || 0 %></b></td></tr>
    11 </table>
    12
    13 <table cellspacing="2" cellpadding="0" border="0" class="tform">
    14 <tr><td height="3"></td></tr>
    15 <tr><td colspan="2"><b><a href="/contenido/webshop/coupon.html">Зарегистрировать &raquo;</a></b></td></tr>
    16
    17 </table>
    18
    19 </fieldset>
    20 <%args>
    21
    22 $status => undef
    23
    24 </%args>
    25 <%init>
    26
    27 my $now = Contenido::DateTime->new;
    28 my $sql = $keeper->SQL->prepare( "select status, count(id) as cnt from webshop_coupons where class = 'webshop::Discount' and ? <= etime group by status" );
    29 $sql->execute( $now->ymd('-').' '.$now->hms );
    30
    31 my %stats;
    32 while ( my $ln = $sql->fetchrow_hashref ) {
    33 $stats{$ln->{status}} = $ln->{cnt};
    34 }
    35 # my $active = $keeper->get_documents (
    36 # class => 'webshop::Coupon',
    37 # status => 1,
    38 # count => 1,
    39 # interval => [$now, $now],
    40 # );
    41 # my $used = $keeper->get_documents (
    42 # class => 'webshop::Coupon',
    43 # status => 3,
    44 # count => 1,
    45 # interval => [$now, $now],
    46 # );
    47
    48 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/components/discount_browse.msn

     
    1 <script type="text/javascript">
    2 <!--
    3 var aIDs = new Array (<% scalar @$documents ? join (',', map { $_->id } @$documents) : '' %>);
    4 function delete_check () {
    5 for ( var i = 0; i < aIDs.length; i++ ) {
    6 var sFieldName = 'delete_' + aIDs[i] + '_id';
    7 var oField = document.forms['section_browse'].elements[sFieldName];
    8 if ( oField.checked ) {
    9 oField.checked = 0;
    10 } else {
    11 oField.checked = 1;
    12 }
    13 }
    14 }
    15 //-->
    16 </script>
    17 <form name="section_browse" action="coupons.html" method="POST">
    18 <table width="100%" border="0" cellpadding="4" cellspacing="0" class="tlistdocs">
    19 <tr bgcolor="#efefef">
    20 <th><a href="javascript:delete_check()" onclick="delete_check(); return false;"><img src="/contenido/i/actions/delete.gif" width="14" height="17" alt="Удаление документов" align="absmiddle" border="0" hspace="1"></a></th>
    21 %
    22 % foreach (@$columns) {
    23 <th><% $_->{shortname} || $_->{rusname} %></th>
    24 % }
    25 %
    26 </tr>
    27 %
    28 % unless (@$documents) {
    29 <tr><td align="center" colspan="<% scalar @$columns %>">Документы не найдены</td></tr>
    30 % }
    31 % foreach my $document (@$documents) {
    32 %
    33 % next unless ref($document);
    34 % my $document_access = $user->section_accesses($user, $document->section);
    35 %
    36 <tr valign="top">
    37 <td nowrap>\
    38 % if ($document_access == 2) {
    39 % $delete_status = 1;
    40 <input type="checkbox" name="<% 'delete_'.$document->id.'_id' %>">
    41 % } else {
    42 &nbsp;
    43 % }
    44 </td>
    45 %
    46 % for my $col (@$columns) {
    47 % if ($col->{attr} eq '_sort_') {
    48 %
    49 <td width="20px"><% $document->{sorder} %>&nbsp;<a
    50 href="document_move.html?id=<% $document->{id} %>&move=up&s=<% $id %><% $params_unsection ? '&'.$params_unsection : '' %>"><img
    51 src="/contenido/i/ico-up-9x10.gif" border=0 alt="Переместить документ на шаг вверх"></a>&nbsp;<a
    52 href="document_move.html?id=<% $document->{id} %>&move=down&s=<% $id %><% $params_unsection ? '&'.$params_unsection : '' %>"><img
    53 src="/contenido/i/ico-down-9x10.gif" border=0 alt="Переместить документ на шаг вниз"></a>\
    54 %
    55 % } elsif ($col->{attr} eq 'dtime') {
    56 %
    57 <td nowrap><& "/contenido/components/show_dtime.msn", dtime=>$document->{dtime} &>\
    58 %
    59 % } elsif ($col->{attr} eq 'name') {
    60 %
    61 <td><span<% $document->contenido_status_style ? ' style="' . $document->contenido_status_style . '"' : '' %> class="<% $document->status ? '':'hiddensect' %>">\
    62 %
    63 % my $name=$document->name ? $document->name : 'Безымянный документ N'.$document->id;
    64 % if ($document_access == 2) {
    65 %
    66 <a<% $document->contenido_status_style ? ' style="' . $document->contenido_status_style . '"' : '' %> href="./coupon.html?id=<% $document->id %><% $params_unclassed ? '&'.$params_unclassed : '' %>"><% $name | h %>&nbsp;</a>\
    67 %
    68 % } else {
    69 %
    70 <% $name | h %>&nbsp;\
    71 %
    72 % }
    73 %
    74 </span>\
    75 %
    76 % } elsif ($col->{attr} eq 'id') {
    77 %
    78 <td><span class="<% $document->status ? '':'hiddensect' %>">\
    79 % if ($document_access == 2) {
    80 <a href="document.html?id=<% $document->id %>&class=<% $document->class %><% $params_unclassed ? '&'.$params_unclassed : '' %>"><% $document->id %>&nbsp;</a>\
    81 % } else {
    82 <% $document->id %>&nbsp;\
    83 % }
    84 </span>\
    85 %
    86 % } elsif ( exists $col->{inline} && $col->{inline} ) {
    87 % $inline_status = 1;
    88 % my $attr = $col->{attr};
    89 % if ( $col->{type} =~ /^(string|integer|float)$/ && $col->{inline} ) {
    90 % my $style = $col->{inline_style} ? $col->{inline_style} : ($col->{type} =~ /^(integer|float)$/ ? 'text-align:right; ' : '' );
    91 <td><input type="text" name="<% 'update_'.$document->id.'_'.$attr %>" value="<% $document->$attr %>" style="<% $col->{inline_width} ? 'width:'.$col->{inline_width}.'px;' : 'width:65px; ' %> <% $col->{inline_style} || '' %>">
    92 % } elsif ($col->{type} eq 'checkbox') {
    93 % my $checked = $document->$attr ? ' checked' : '';
    94 <td align="center"><input type="checkbox" name="<% 'update_'.$document->id.'_'.$attr %>"<% $checked %>>
    95 % } elsif ($col->{type} eq 'select') {
    96 % my $options = {};
    97 % if ($toopi && (ref($toopi) eq 'HASH') && (exists($toopi->{$document->class}))) {
    98 % %{ $options } = %{ $toopi->{$document->class} };
    99 % }
    100 % my $values = $options->{$col->{attr}};
    101 <td><select name="<% 'update_'.$document->id.'_'.$attr %>">
    102 % if ( ref $values eq 'ARRAY' ) {
    103 % foreach my $val ( @$values ) {
    104 % my $selected = $val eq $document->$attr ? ' selected' : '';
    105 <option value="<% $val %>"<% $selected %>><% $val %>
    106 % }
    107 % }
    108 </select>
    109 % } elsif ($col->{type} eq 'status') {
    110 % my $cases = $col->{cases};
    111 % if ( ref $cases eq 'ARRAY' ) {
    112 <td><select name="<% 'update_'.$document->id.'_'.$attr %>" style="<% $col->{inline_width} ? 'width:'.$col->{inline_width}.'px;' : '' %> <% $col->{inline_style} || '' %>">
    113 % foreach my $case ( @$cases ) {
    114 % my $selected = $case->[0] eq $document->$attr ? ' selected' : '';
    115 <option value="<% $case->[0] %>"<% $selected %>><% $case->[1] %>
    116 % }
    117 </select>
    118 % }
    119 % }
    120 %
    121 % } elsif ($col->{attr} eq 'class') {
    122 %
    123 <td><% $document->class_name %>&nbsp;<font color="#999999">(<% $document->class %>)</font>\
    124 %
    125 % } elsif ($col->{type} eq 'datetime') {
    126 %
    127 <td nowrap><& "/contenido/components/show_dtime.msn", dtime=>$document->{$col->{attr}} &>\
    128 %
    129 % } elsif ($col->{attr} eq '_act_') {
    130 %
    131 <td nowrap>\
    132 % if ($document_access == 2) {
    133 %
    134 <a href="./coupon.html?id=<% $document->id %><% $params_unclassed ? '&'.$params_unclassed : '' %>" title="Редактировать документ"><img
    135 src="/contenido/i/actions/edit.gif" width="15" height="17" alt="Редактировать документ" align="absmiddle" border="0" hspace="1">редактировать</a>\
    136 %#<a href="confirm.html?id=<% $document->id %>&action=documents_deletion&from=<% $section->id %>&class=<% $document->class %><% $params_unclassed ? '&'.$params_unclassed : '' %>" title="Удалить документ"><img
    137 %# src="/contenido/i/actions/delete.gif" width="14" height="17" alt="Удалить документ" align="absmiddle" border="0" hspace="1"></a>\
    138 <br>\
    139 %
    140 % } else {
    141 &nbsp;\
    142 % }
    143 % if ( $inline_status ) {
    144 <input type="hidden" name="update_<% $document->id %>_class" value="<% $document->class %>">
    145 % }
    146 % if ( $delete_status ) {
    147 <input type="hidden" name="delete_<% $document->id %>_class" value="<% $document->class %>">
    148 % }
    149 %
    150 % } else {
    151 %
    152 % if ($col->{type} eq 'date') {
    153 % my $date=$document->{$col->{attr}};
    154 % $date=~/(\d{4}-\d{2}-\d{2})/;
    155 <td nowrap align="right"><% $1 || '&nbsp;' %>\
    156 % } elsif ($col->{type} eq 'datetime') {
    157 <td nowrap align="right"><% $document->{$col->{attr}} || '&nbsp;' %>\
    158 % } elsif ($col->{type} eq 'integer') {
    159 <td align="right"><% $document->{$col->{attr}} %>&nbsp;\
    160 % } elsif ($col->{type} eq 'lookup' || $col->{type} eq 'pickup') {
    161 <td align="left">\
    162 % my $id = $document->{$col->{attr}};
    163 % if ($id) {
    164 % my ($doc)=$keeper->get_documents( ( ref($col->{lookup_opts}) ? %{$col->{lookup_opts}} : () ), id=>$id);
    165 % if ($doc) {
    166 <a href="document.html?id=<% $doc->id %>&class=<% $doc->class %><% $params_unclassed ? '&'.$params_unclassed : '' %>"><% $doc->name || $doc->id %></a>&nbsp;\
    167 % } else {
    168 <span class="hiddensect"><% $document->{$col->{attr}} %>???</span>\
    169 % }
    170 % } else {
    171 <span class="hiddensect">NULL</span>\
    172 % }
    173 % } elsif ($col->{type} eq 'status') {
    174 % my $status_map = ref $col->{cases} eq 'ARRAY' ? $col->{cases} : $keeper->default_status();
    175 % my ($doc_status) = grep { $_->[0] eq $document->{$col->{attr}} } @$status_map;
    176 % $doc_status ||= [$document->{$col->{attr}}, 'Неизвестный'];
    177 <td nowrap><% $doc_status->[1].'('.$doc_status->[0].')' %>\
    178 % } else {
    179 <td><% defined($document->{$col->{attr}}) ? $document->{$col->{attr}} : '&nbsp;' %>\
    180 % }
    181 % }
    182 </td>
    183 %
    184 % } #- for @columns
    185 %
    186 </tr>
    187 % } #- foreach @documents
    188 </table>
    189 % if ( ref $filter eq 'HASH' ) {
    190 % while ( my ($key, $value) = each %$filter ) {
    191 % next if $key eq 's';
    192 <input type="hidden" name="<% $key %>" value="<% $value |h %>">
    193 % }
    194 % }
    195 % if ( $inline_status || $delete_status ) {
    196 <div style="text-align:right; padding:10px 0;">
    197 % if ( $inline_status ) {
    198 <input type="submit" name="update" value="Сохранить изменения" class="input_btn">
    199 % }
    200 % if ( $delete_status ) {
    201 <input type="submit" name="delete" value="Удалить выбранные" class="input_btn" onclick="return confirm('Все отмеченные позиции будут удалены');">
    202 % }
    203 </div>
    204 % }
    205 </form>
    206 <%args>
    207
    208 $documents => undef
    209 $columns => undef
    210 $id => undef
    211 $filter => undef
    212
    213 </%args>
    214 <%init>
    215
    216 return unless ref $documents eq 'ARRAY';
    217 return unless ref $columns eq 'ARRAY';
    218
    219 my $toopi = $project->documents();
    220 my $inline_status = 0;
    221 my $delete_status = 0;
    222 my $params = ref $filter eq 'HASH' ? join ('&', map { $_.'='.$filter->{$_} } keys %$filter ) : '';
    223 my $params_unclassed = ref $filter eq 'HASH' ? join ('&', map { $_.'='.$filter->{$_} } grep { $_ ne 'class' } keys %$filter ) : '';
    224 my $params_unsection = ref $filter eq 'HASH' ? join ('&', map { $_.'='.$filter->{$_} } grep { $_ ne 's' } keys %$filter ) : '';
    225
    226
    227 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/discounts.html

     
    1 <& "/contenido/components/header.msn" &>
    2
    3 <style>
    4 <!--
    5 .inverted td { font-weight:bold; color:white; background-color:#8093B0; }
    6 .inverted td a { color:white; font-weight:bold; }
    7 //-->
    8 </style>
    9
    10 <% spacer( h=>10 ) %>
    11
    12 <table width="100%" cellspacing="0" cellpadding="0" border="0">
    13 <tr valign="top">
    14 <td width="35%">
    15
    16 <& /contenido/webshop/components/block_order_status_changer.msn &>
    17
    18 <& /contenido/webshop/components/block_coupons.msn, status => $cst &>
    19
    20 </td>
    21 <td width="1%">&nbsp;</td>
    22 <td width="65%">
    23
    24 <fieldset>
    25 <legend>Скидки со статусом "<span style="color:yellow"><% $current_status->[1] %></span>"</legend>
    26
    27 % if ( $total ) {
    28
    29 <div style="font-size:75%; font-family:Arial;">
    30 <& /inc/pages_.msn, p=>$p, n=>$size, total=>$total, params=>\%filter_params, &>
    31 <div style="height:5px"><spacer type="block" height="5"></div>
    32 </div>
    33
    34 <& /contenido/webshop/components/coupon_browse.msn, documents => \@documents, columns => \@columns, filter => \%filter_params, status => $cst, %ARGS &>
    35
    36 <div style="font-size:75%; font-family:Arial;">
    37 <& /inc/pages_.msn, p=>$p, n=>$size, total=>$total, params=>\%filter_params, &>
    38 <div style="height:5px"><spacer type="block" height="5"></div>
    39 </div>
    40
    41 % } else {
    42 <h4 align="center"><i>---- Нет документов -----</i></h4>
    43 % }
    44
    45 </td>
    46 <td width="1%">&nbsp;</td>
    47 </tr>
    48 </table>
    49
    50 </body>
    51 </html>
    52 <%args>
    53
    54 $cst => 1
    55 $p => 1
    56 $delete => undef
    57
    58 </%args>
    59 <%init>
    60
    61 my %filter_params;
    62
    63 my (@documents, $total);
    64 $filter_params{cst} = $cst if $cst != 1;
    65 my $size = 40;
    66
    67 @documents = $keeper->get_documents(
    68 class => 'webshop::Discount',
    69 status => $cst,
    70 limit => $size,
    71 offset => ($p-1)*$size,
    72 order_by => 'dtime desc',
    73 );
    74 $total = $keeper->get_documents(
    75 class => 'webshop::Discount',
    76 status => $cst,
    77 count => 1,
    78 );
    79 my @structure = webshop::Discount->new( $keeper->{webshop} )->structure;
    80 my @columns = sort { $a->{column} <=> $b->{column} }
    81 grep { $_->{column} } @structure;
    82 push @columns, {attr => '_act_', rusname => 'Действия'};
    83 my ($status_map) = grep { $_->{attr} eq 'status' } @structure;
    84 my ($current_status) = grep { $_->[0] == $cst } @{$status_map->{cases}};
    85
    86 my $active_rights = $m->comp('/contenido/webshop/subs/user_rights.msn');
    87 if ( !$active_rights && $delete ) {
    88 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
    89 my %deleted;
    90 while ( my ($field, $value) = each %ARGS ) {
    91 if ( $field =~ /^delete_(\d+)_(\w+)$/ ) {
    92 my $oid = $1;
    93 my $attr = $2;
    94 $deleted{$oid}{$attr} = $value;
    95 }
    96 }
    97 my %classes = map { $_->{class} => 1 } values %deleted;
    98 foreach my $delete_class ( keys %classes ) {
    99 my @ids;
    100 while ( my ($oid, $attr) = each %deleted) {
    101 push @ids, $oid if exists $attr->{id} && $attr->{id} && ($attr->{class} eq $delete_class);
    102 }
    103 my @objects = $keeper->get_documents (
    104 id => \@ids,
    105 class => $delete_class
    106 ) if @ids;
    107 foreach my $object ( @objects ) {
    108 my $document_access = $user->section_accesses($user, $object->section);
    109 next unless $document_access == 2;
    110 $object->delete;
    111 }
    112 }
    113 $m->redirect("/contenido/webshop/".($return_params ? '?'.$return_params : ''));
    114 }
    115
    116 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/index.html

     
    16 16 <& /contenido/webshop/components/block_order_status_changer.msn, status => $ost &>
    17 17
    18 18 <& /contenido/webshop/components/block_coupons.msn &>
    19 %#<& /contenido/webshop/components/block_discounts.msn &>
    19 20 <& /contenido/webshop/components/block_order_finder.msn &>
    20 21
    21 22 </td>
  • utf8/plugins/webshop/lib/webshop/Discount.pm

     
    10 10 sub extra_properties
    11 11 {
    12 12 return (
    13 { 'attr' => 'code', 'hidden' => 1, 'column' => undef },
    13 14 { 'attr' => 'class', 'column' => undef },
    15 { 'attr' => 'dtime', 'rusname' => 'Начало действия скидки' },
    16 { 'attr' => 'etime', 'rusname' => 'Окончание действия скидки' },
    14 17 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус',
    15 18 'cases' => [
    16 19 [0, 'Скидка не активна'],
     
    28 31 allow_null => 1,
    29 32 rem => 'Список разделов, на содержимое которых распространяется скидка по купону',
    30 33 },
    31 { 'attr' => 'discount', 'type' => 'string', 'rusname' => 'Скидка на сумму заказа (число или процент)', shortname => 'Скидка',
    32 default => 0, column => 2 },
    33 { 'attr' => 'min_sum', 'type' => 'string', 'rusname' => 'Минимальная сумма, на которую действует скидка', default => 0 },
    34 { 'attr' => 'min_sum', 'type' => 'string', 'rusname' => 'Порог суммы, с которого действует скидка',
    35 default => 0, column => 2, shortname => 'Сумма заказа' },
    36 { 'attr' => 'discount', 'type' => 'string', 'rusname' => 'Размер скидки (число или процент)', shortname => 'Скидка',
    37 default => 0, column => 3 },
    34 38 )
    35 39 }
    36 40
  • utf8/plugins/webshop/lib/webshop/Init.pm

     
    39 39 ));
    40 40
    41 41 sub init {
    42 push @{ $state->{'available_documents'} }, qw(webshop::Basket webshop::Order webshop::Delivery webshop::Payment webshop::Coupon webshop::Country webshop::Area webshop::Town);
    42 push @{ $state->{'available_documents'} }, qw(webshop::Basket webshop::Order webshop::Delivery webshop::Payment webshop::Coupon webshop::Discount webshop::Country webshop::Area webshop::Town);
    43 43 push @{ $state->{'available_sections'} }, qw(webshop::DeliverySection webshop::PaymentSection webshop::RegionSection);
    44 44 push @{ $state->{'available_links'} }, qw(webshop::CouponItemLink webshop::OrderCouponLink);
    45 45 0;
  • utf8/plugins/webshop/lib/webshop/Keeper.pm

     
    420 420 }
    421 421 my $basket = exists $opts{basket} ? $opts{basket} : $self->get_basket( %opts );
    422 422
    423 my $now = Contenido::DateTime->new;
    423 424 my @discounts = $keeper->get_documents(
    424 425 class => 'webshop::Discount',
    425 426 status => 1,
    426 %dopts
    427 interval=> [$now, $now],
    428 %dopts,
    427 429 );
    430 return 0 unless @discounts;
    431 my @summoned = sort { $b->min_sum <=> $a->min_sum } grep { $_->min_sum && $_->discount && $_->min_sum =~ /^\d+$/ } @discounts;
    432 my ($total, $sum) = $self->basket_count( $basket );
    433 return 0 unless $sum;
    434 my $result = 0;
    435 foreach my $discount ( @summoned ) {
    436 if ( $sum > $discount->min_sum ) {
    437 my $res = 0;
    438 my $value = $discount->discount;
    439 $value =~ s/\s//sg;
    440 if ( $value =~ /([\d\.]+)%/ ) {
    441 my $proc = $1;
    442 $res = $sum / 100 * $proc;
    443 } elsif ( $value =~ /([\d\.]+)/ ) {
    444 my $res = $1;
    445 }
    446 $result = $res if $res > $result;
    447 }
    448 }
    449 $result = 0 if $result >= $sum;
    450 return $result;
    428 451 }
    429 452
    430 453
  • utf8/plugins/webshop/lib/webshop/Order.pm

     
    81 81 sub sum_formatted {
    82 82 my $self = shift;
    83 83
    84 my $price = $self->sum;
    84 my $price = $self->sum_total;
    85 85 $price = reverse $price;
    86 86 $price =~ s/(\d{3})/$1\ /g;
    87 87 $price = reverse $price;
  • utf8/plugins/webshop/lib/webshop/SQL/CouponsTable.pm

     
    27 27 _uid_filter
    28 28 _pid_filter
    29 29 _code_filter
    30 _interval_filter
    30 31 )];
    31 32
    32 33 sub available_filters {
     
    153 154 return undef unless ref $opts{interval}->[0] && ref $opts{interval}->[1];
    154 155 return undef if DateTime->compare($opts{interval}->[0], $opts{interval}->[1]) == 1;
    155 156
    156 my $wheres = "d.dtime <= ? and d.etime >= ?";
    157 my $wheres = "date_trunc('day', d.dtime) <= ? and date_trunc('day', d.etime) >= ?";
    157 158 my @values = ($opts{interval}->[1]->ymd('-'), $opts{interval}->[0]->ymd('-'));
    158 159
    159 160 return ($wheres, \@values);