Revision 425
- Date:
- 2014/03/06 23:28:32
- Files:
-
- /utf8/plugins/webshop/comps/contenido/webshop/components/block_coupons.msn (Diff) (Checkout)
- /utf8/plugins/webshop/comps/contenido/webshop/components/block_discounts.msn (Diff) (Checkout)
- /utf8/plugins/webshop/comps/contenido/webshop/components/discount_browse.msn (Diff) (Checkout)
- /utf8/plugins/webshop/comps/contenido/webshop/discounts.html (Diff) (Checkout)
- /utf8/plugins/webshop/comps/contenido/webshop/index.html (Diff) (Checkout)
- /utf8/plugins/webshop/lib/webshop/Discount.pm (Diff) (Checkout)
- /utf8/plugins/webshop/lib/webshop/Init.pm (Diff) (Checkout)
- /utf8/plugins/webshop/lib/webshop/Keeper.pm (Diff) (Checkout)
- /utf8/plugins/webshop/lib/webshop/Order.pm (Diff) (Checkout)
- /utf8/plugins/webshop/lib/webshop/SQL/CouponsTable.pm (Diff) (Checkout)
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">Зарегистрировать »</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 43 % } 44 </td> 45 % 46 % for my $col (@$columns) { 47 % if ($col->{attr} eq '_sort_') { 48 % 49 <td width="20px"><% $document->{sorder} %> <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> <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 %> </a>\ 67 % 68 % } else { 69 % 70 <% $name | h %> \ 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 %> </a>\ 81 % } else { 82 <% $document->id %> \ 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 %> <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 \ 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 || ' ' %>\ 156 % } elsif ($col->{type} eq 'datetime') { 157 <td nowrap align="right"><% $document->{$col->{attr}} || ' ' %>\ 158 % } elsif ($col->{type} eq 'integer') { 159 <td align="right"><% $document->{$col->{attr}} %> \ 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> \ 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}} : ' ' %>\ 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%"> </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%"> </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);