Revision 198

Date:
2012/03/15 18:29:29
Author:
ahitrov
Revision Log:
Simple webshop support plugin
Files:

Legend:

 
Added
 
Removed
 
Modified
  • utf8/plugins/webshop/comps/contenido/webshop/autohandler

     
    1 <%init>
    2
    3 $r->content_type('text/html');
    4 $m->call_next();
    5
    6 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/components/block_order_status_changer.msn

     
    1 <fieldset>
    2 <legend>Выбор заказов по статусу</legend>
    3
    4 <table width="100%" border="0" cellpadding="3" cellspacing="0" class="tlistdocs">
    5 <tr bgcolor="#efefef">
    6 <th align="center" width="1%">ID</th>
    7 <th>Статус</th>
    8
    9 % foreach my $case ( @cases ) {
    10 % next unless $case->[0];
    11 % my $style = $status && $case->[0] == $status ? 'inverted' : '';
    12 <tr class="<% $style %>">
    13 <td><% $case->[0] %></td>
    14 <td><table cellpadding="0" cellspacing="0" border="0">
    15 <tr valign="top">
    16 <td width="10">&nbsp;</td>
    17 <td><a href="./?ost=<% $case->[0] %>"><% Encode::encode('utf-8', ucfirst(Encode::decode('utf-8',$case->[1]))) %></a></td>
    18 </tr>
    19 </table>
    20 </td>
    21 </tr>
    22 % }
    23
    24 </table>
    25
    26 </fieldset>
    27 <%args>
    28
    29 $status => undef
    30
    31 </%args>
    32 <%init>
    33
    34 my ($prop) = grep { $_->{attr} eq 'status' } webshop::Order->new( $keeper->{webshop} )->structure;
    35 my @cases = @{$prop->{cases}};
    36
    37 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/components/object_form.msn

     
    1 <!-- Форма для редактирования объекта -->
    2 <a name="top"></a>
    3 <form enctype="multipart/form-data" action="<% $PROTOS->{$proto}->[1] %>" method="POST" name="form" onSubmit="javascript:Save()">
    4 <table border="0" width="100%" cellspacing="0" cellpadding="6">
    5 <tr>
    6 <td style="font-size:110%;">
    7 <b><% (ref($object) && $object->id() ) ? 'Редактирование' : 'Создание' %> <% $PROTOS->{$proto}->[0] %> типа "<% $object->class_name() %>"</b>
    8 </td>
    9 <td align="right">
    10 % unless ( $proto eq 'sections' && $object->id == 1 ) {
    11 <input type="submit" value="Сохранить" class="input_btn">
    12 % if (( $proto eq 'documents' ) || ( $proto eq 'sections' )) {
    13 <input type="submit" name="_save_and_leave" value="Сохранить и выйти" class="input_btn">
    14 <input type="submit" name="_save_and_again" value="Сохранить и создать новый" class="input_btn">
    15 % }
    16 % }
    17 </td>
    18 </tr>
    19 </table>
    20
    21 % if ( $m->comp_exists ('/contenido/components/object_context_menu.msn') ) {
    22 <div style="text-align:right;"><& '/contenido/components/object_context_menu.msn', object => $object &></div>
    23 % }
    24
    25 <center>
    26 <table width="100%" cellpadding="0" cellspacing="0" border="0">
    27 <tr>
    28 <td bgcolor="#999999">
    29 <table width="100%" cellpadding="0" cellspacing="1" border="0">
    30 <tr><td valign="top" width="80%" bgcolor="#ffffff">
    31 <center>
    32 <table width="98%" cellpadding="1" cellspacing="0" border="0">
    33
    34 <%perl>
    35
    36 my @properties = $object->structure();
    37
    38 for (0..$#properties)
    39 {
    40
    41 my $prop = $properties[$_];
    42 next if ($prop->{hidden} == 1) || ($prop->{type} eq 'image') || ($prop->{type} eq 'external') || ($prop->{type} =~ /^array/i) || ($prop->{type} =~ /^image/) || ($prop->{type} eq 'multimedia') || ($prop->{type} eq 'multimedia_new') || ($prop->{type} eq 'audio');
    43
    44 </%perl>
    45 <tr><td height="8"></td></tr>
    46 <tr><td nowrap>
    47 <table cellpadding="0" cellspacing="0" border="0">
    48 <tr>
    49 % if( ( $prop->{type} eq 'flag' ) || ($prop->{type} eq 'checkbox') )
    50 % {
    51 <td><& "/contenido/components/inputs/checkbox.msn", prop => $prop, object=>$object, options=>$options, name => $prop->{attr}, check => $object->{$prop->{attr}}, id => $object->id() &></td>
    52 % }
    53 <td nowrap><b><% $prop->{rusname} %></b>&nbsp;/</td>
    54 <td align="right" nowrap><font color="#888888" size="-1">&nbsp;name="<% $prop->{attr} %>"</font></td>
    55 % if( $prop->{readonly} )
    56 % {
    57 <td align="right" nowrap>&nbsp;/&nbsp;<font color="#CC0000" size="-1">Значение нельзя изменить</font></td>
    58 % }
    59 </tr>
    60 </table>
    61 </td></tr>
    62 % if ($prop->{type} eq 'parent')
    63 % {
    64 <tr><td><& "/contenido/components/inputs/$prop->{type}.msn", prop => $prop, object=>$object, options=>$options, name => $prop->{attr}, check => ($object->{$prop->{attr} } || $prop->{default} || $sect_id ), id => $object->id() &></td></tr>
    65 % }
    66 % elsif( ( $prop->{type} ne 'flag' ) && ($prop->{type} ne 'checkbox') )
    67 % {
    68 <tr><td><& "/contenido/components/inputs/$prop->{type}.msn", prop => $prop, object=>$object, options => $options, name => $prop->{attr}, check => $object->{$prop->{attr}}, id => ($object->id() || 0) &></td></tr>
    69 % }
    70 % }
    71 <tr>
    72 <td><br>
    73
    74 % for (0..$#properties)
    75 % {
    76 % my $prop = $properties[$_];
    77 % next if ($prop->{hidden} != 1);
    78 % next if ($prop->{attr} eq 'id' && $clone);
    79 <input type="hidden" name="<% $prop->{attr} %>" value="<% html_escape($object->{ $prop->{attr} }) %>">
    80 % }
    81 <input type="hidden" name="sect_id" value="<% $sect_id %>">
    82 %#если класса в свойствах обьекта нет все равно надо его пробросить как hidden
    83 % unless (grep {$_->{attr} eq 'class'} @properties) {
    84 <input type="hidden" name="class" value="<% html_escape($object->{class}) %>">
    85 % }
    86 % if ( $clone ) {
    87 <input type="hidden" name="clone" value="<% $object->id %>">
    88 % }
    89 <input type="hidden" name="save" value="1">
    90
    91 </td>
    92 </tr>
    93 </table>
    94 </center>
    95
    96 </td>
    97 <td valign="top" bgcolor="#efefef">
    98 <div style="width:270px"><spacer type="block" width="270"></div>
    99 <div><iframe name="DocFinder" id="DocFinder" src="/contenido/find_document.html" frameborder="0"
    100 marginheight="0" marginwidth="0" width="100%" height="0"></iframe></div>
    101 <table cellpadding="5" cellspacing="0" border="0"><tr><td>
    102 <p><font size=+1><b><nobr>Мультимедиа-объекты</nobr> к&nbsp;<% $PROTOS->{$proto}->[2] %></b></font></p>
    103
    104 % for (0..$#properties)
    105 % {
    106 % my $prop = $properties[$_];
    107 %
    108 % if ($prop->{type} eq 'image')
    109 % {
    110 % my $IMAGE = $object->get_image( $prop->{attr} );
    111 % if (ref($IMAGE) ne 'HASH') { next };
    112 <& "/contenido/components/inputs/image.msn",
    113 IMAGE => $IMAGE,
    114 rusname => $prop->{rusname},
    115 prop => $prop, object=>$object,
    116 attr => $prop->{attr},
    117 options => $options,
    118 &>
    119
    120 % } elsif ($prop->{type} eq 'images')
    121 % {
    122 % my $IMAGES = $object->get_image( $prop->{attr} );
    123 % if (ref($IMAGES) ne 'HASH') { next };
    124 % my $MN = $IMAGES->{maxnumber}+0;
    125 % for my $mn (1..$MN)
    126 % {
    127 % my $IMAGE = $IMAGES->{'image_'.$mn};
    128
    129 <& "/contenido/components/inputs/image.msn",
    130 rusname => $prop->{rusname},
    131 prop => $prop, object=>$object,
    132 attr => $prop->{attr}.'_'.$mn,
    133 IMAGE => $IMAGE,
    134 options => $options,
    135 &>
    136
    137 % }
    138 % my $ME = exists $prop->{empty_slots} ? $prop->{empty_slots} : 5;
    139 % $ME = ($ME + $IMAGES->{maxnumber}) >= 100 ? 0 : (100 - $IMAGES->{maxnumber} < $ME ? 100 - $IMAGES->{maxnumber} : $ME );
    140 % for my $mn (1..$ME)
    141 % {
    142
    143
    144 <& "/contenido/components/inputs/image.msn",
    145 IMAGE => {},
    146 rusname => $prop->{rusname},
    147 prop => $prop, object=>$object,
    148 attr => $prop->{attr}.'_'.($MN+$mn),
    149 options => $options,
    150 &>
    151
    152 % }
    153 % } elsif ($prop->{type} eq 'multimedia')
    154 % {
    155 % my $MULTI = $object->get_image( $prop->{attr} );
    156
    157 <& "/contenido/components/inputs/multimedia.msn",
    158 rusname => $prop->{rusname},
    159 prop => $prop, object=>$object,
    160 attr => $prop->{attr},
    161 MULTI => $MULTI,
    162 options => $options,
    163 &>
    164 % } elsif ($prop->{type} eq 'multimedia_new')
    165 % {
    166 % my $MULTI = $object->get_image( $prop->{attr} );
    167
    168 <& "/contenido/components/inputs/multimedia_new.msn",
    169 rusname => $prop->{rusname},
    170 prop => $prop, object=>$object,
    171 attr => $prop->{attr},
    172 MULTI => $MULTI,
    173 options => $options,
    174 &>
    175 % } elsif ($prop->{type} eq 'audio')
    176 % {
    177 % my $MULTI = $object->get_image( $prop->{attr} );
    178
    179 <& "/contenido/components/inputs/audio.msn",
    180 rusname => $prop->{rusname},
    181 prop => $prop, object=>$object,
    182 attr => $prop->{attr},
    183 MULTI => $MULTI,
    184 options => $options,
    185 &>
    186 % }
    187 % }
    188
    189 </table>
    190 </td></tr></table>
    191
    192
    193 </td></tr>
    194 </table>
    195
    196 </td></tr></table>
    197 </center>
    198
    199 <script>
    200 <!--
    201 function updateList(theFild,value,text) {
    202 for (var i = 0; i < theFild.options.length; i++) {
    203 if (theFild.options[i].value == value) {
    204 return false;
    205 }
    206 }
    207 var option_length = theFild.options.length++;
    208 eval("theFild.options[option_length].value=value");
    209 eval("theFild.options[option_length].text=text");
    210
    211 Save(); this.form.submit();
    212
    213 }
    214 //-->
    215 </script>
    216
    217 % unless ( $proto eq 'sections' && $object->id == 1 ) {
    218 <div align="center"><input type="submit" value="Сохранить" class="input_btn">
    219 %# <input type="submit" value="Сохранить изменения в <% $PROTOS->{$proto}->[3] %>" class="input_btn">
    220
    221 %#
    222 %# Как же сохранять эти гребанные связи?
    223 %# onClick="javascript:updateList(parent.opener.links.links,'link_6_20_DefaultLink','test');"
    224 %#
    225
    226
    227 % if ($object->id > 0 && !$clone) {
    228 <input name="delete" type="button" value="Удалить" onClick="javascript:window.location='confirm.html?id=<% $object->id() %>&action=<% $proto %>_deletion&class=<% $object->class() %>'" class="input_btn">\
    229 % }
    230 % if ( ref $filter_params eq 'HASH' ) {
    231 % while ( my ($key, $value) = each %$filter_params ) {
    232 % next if grep { $_->{attr} eq $key } $object->structure();
    233 <input type="hidden" name="<% $key %>" value="<% $value %>">
    234 % }
    235 % }
    236 <input type="hidden" name="control_charset" value="Контроль">
    237 % if (( $proto eq 'documents' ) || ( $proto eq 'sections' )) {
    238 <input type="submit" name="_save_and_leave" value="Сохранить и выйти" class="input_btn">
    239 % unless ( $clone ) {
    240 <input type="submit" name="_save_and_again" value="Сохранить и создать новый" class="input_btn">
    241 % }
    242 % }
    243 </div>
    244 % }
    245 </form>
    246
    247 <%ARGS>
    248
    249 $proto => 'documents'
    250 $object => undef
    251 $clone => undef
    252 $sect_id => 1
    253 $filter_params => undef
    254
    255 </%ARGS>
    256
    257 <%ONCE>
    258 my $PROTOS = {
    259 'documents' => ['документа','document.html','документу','документе'],
    260 'sections' => ['секции','section.html','секции','секции'],
    261 'links' => ['связи','link.html','связи','связи'],
    262 'users' => ['пользователя','users.html','пользователю','пользователе'],
    263 };
    264 </%ONCE>
    265
    266 <%INIT>
    267 return undef unless ref($object);
    268
    269 my $toopi = $project->$proto();
    270 my $options = {};
    271 if ($toopi && (ref($toopi) eq 'HASH') && (exists($toopi->{ $object->class }))) {
    272 %{ $options } = %{ $toopi->{ $object->class } };
    273 }
    274 </%INIT>
  • utf8/plugins/webshop/comps/contenido/webshop/components/order_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="./" 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 'dtime') {
    48 %
    49 <td nowrap><& "/contenido/components/show_dtime.msn", dtime=>$document->{dtime} &>\
    50 % if ($document->{ctime} ne $document->{mtime}) {
    51 % my $colortime = '#c66';
    52 <div style="color:<% $colortime %>;"><& "/contenido/components/show_dtime.msn", dtime=>$document->{mtime} &></div>\
    53 % }
    54 %
    55 % } elsif ($col->{attr} eq 'name') {
    56 % my $style = $document->contenido_status_style ? ' style="'.$document->contenido_status_style.'"' : '';
    57 % my ($a1, $a2) = $href ? ('<a href="./'.$href.'?id='.$document->id.($params_unclassed ? '&'.$params_unclassed : '').'"'.$style.'>','</a>') : ('','');
    58 <td><span<% $style %> class="<% $document->status ? '':'hiddensect' %>">\
    59 %
    60 % my $name=$document->name ? $document->name : 'Безымянный документ N'.$document->id;
    61 <% $a1 %><% $name | h %><% $a2 %>\
    62 %
    63 </span>\
    64 %
    65 % } elsif ($col->{attr} eq 'id') {
    66 %
    67 <td><span class="<% $document->status ? '':'hiddensect' %>">\
    68 % if ($document_access == 2) {
    69 <a href="document.html?id=<% $document->id %>&class=<% $document->class %><% $params_unclassed ? '&'.$params_unclassed : '' %>"><% $document->id %>&nbsp;</a>\
    70 % } else {
    71 <% $document->id %>&nbsp;\
    72 % }
    73 </span>\
    74 %
    75 % } elsif ( exists $col->{inline} && $col->{inline} ) {
    76 % $inline_status = 1;
    77 % my $attr = $col->{attr};
    78 % if ( $col->{type} =~ /^(string|integer|float)$/ && $col->{inline} ) {
    79 % my $style = $col->{inline_style} ? $col->{inline_style} : ($col->{type} =~ /^(integer|float)$/ ? 'text-align:right; ' : '' );
    80 <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} || '' %>">
    81 % } elsif ($col->{type} eq 'checkbox') {
    82 % my $checked = $document->$attr ? ' checked' : '';
    83 <td align="center"><input type="checkbox" name="<% 'update_'.$document->id.'_'.$attr %>"<% $checked %>>
    84 % } elsif ($col->{type} eq 'select') {
    85 % my $options = {};
    86 % if ($toopi && (ref($toopi) eq 'HASH') && (exists($toopi->{$document->class}))) {
    87 % %{ $options } = %{ $toopi->{$document->class} };
    88 % }
    89 % my $values = $options->{$col->{attr}};
    90 <td><select name="<% 'update_'.$document->id.'_'.$attr %>">
    91 % if ( ref $values eq 'ARRAY' ) {
    92 % foreach my $val ( @$values ) {
    93 % my $selected = $val eq $document->$attr ? ' selected' : '';
    94 <option value="<% $val %>"<% $selected %>><% $val %>
    95 % }
    96 % }
    97 </select>
    98 % } elsif ($col->{type} eq 'status') {
    99 % my $cases = $col->{cases};
    100 % if ( ref $cases eq 'ARRAY' ) {
    101 <td><select name="<% 'update_'.$document->id.'_'.$attr %>" style="<% $col->{inline_width} ? 'width:'.$col->{inline_width}.'px;' : '' %> <% $col->{inline_style} || '' %>">
    102 % foreach my $case ( @$cases ) {
    103 % my $selected = $case->[0] eq $document->$attr ? ' selected' : '';
    104 <option value="<% $case->[0] %>"<% $selected %>><% $case->[1] %>
    105 % }
    106 </select>
    107 % }
    108 % }
    109 %
    110 % } elsif ($col->{attr} eq 'class') {
    111 %
    112 <td><% $document->class_name %>&nbsp;<font color="#999999">(<% $document->class %>)</font>\
    113 %
    114 % } elsif ($col->{type} eq 'datetime') {
    115 %
    116 <td nowrap><& "/contenido/components/show_dtime.msn", dtime=>$document->{$col->{attr}} &>\
    117 %
    118 % } elsif ($col->{attr} eq '_act_') {
    119 % my $actions;
    120 % if ( $document->$user_id == $user->id ) {
    121 % $actions = join (' | ', map { '<a href="./'.$_->{href}.'?id='.$document->id.($params_unclassed ? '&'.$params_unclassed : '').'">'.$_->{name}.'</a>' } @actions);
    122 % } else {
    123 % my $profile = exists $users{$document->$user_id} ? $users{$document->$user_id} : undef;
    124 % unless ( ref $profile ) {
    125 % $profile = $keeper->get_user_by_id( $document->$user_id );
    126 % $users{$profile->id} = $profile if ref $profile;
    127 % }
    128 % if ( ref $profile ) {
    129 % $actions = $profile->name;
    130 % } else {
    131 % $actions = join (' | ', map { '<a href="./'.$_->{href}.'?id='.$document->id.($params_unclassed ? '&'.$params_unclassed : '').'">'.$_->{name}.'</a>' } @actions);
    132 % }
    133 % }
    134 <td nowrap><% $actions %>\
    135 % if ( $inline_status ) {
    136 <input type="hidden" name="update_<% $document->id %>_class" value="<% $document->class %>">
    137 % }
    138 % if ( $delete_status ) {
    139 <input type="hidden" name="delete_<% $document->id %>_class" value="<% $document->class %>">
    140 % }
    141 %
    142 % } else {
    143 %
    144 % if ($col->{type} eq 'date') {
    145 % my $date=$document->{$col->{attr}};
    146 % $date=~/(\d{4}-\d{2}-\d{2})/;
    147 <td nowrap align="right"><% $1 || '&nbsp;' %>\
    148 % } elsif ($col->{type} eq 'datetime') {
    149 <td nowrap align="right"><% $document->{$col->{attr}} || '&nbsp;' %>\
    150 % } elsif ($col->{type} eq 'integer') {
    151 <td align="right"><% $document->{$col->{attr}} %>&nbsp;\
    152 % } elsif ($col->{type} eq 'lookup') {
    153 <td align="left">\
    154 % my $id = $document->{$col->{attr}};
    155 % if ($id) {
    156 % my ($doc)=$keeper->get_documents( ( ref($col->{lookup_opts}) ? %{$col->{lookup_opts}} : () ), id=>$id);
    157 % if ($doc) {
    158 <a href="document.html?id=<% $doc->id %>&class=<% $doc->class %><% $params_unclassed ? '&'.$params_unclassed : '' %>"><% $doc->name || $doc->id %></a>&nbsp;\
    159 % } else {
    160 <span class="hiddensect"><% $document->{$col->{attr}} %>???</span>\
    161 % }
    162 % } else {
    163 <span class="hiddensect">NULL</span>\
    164 % }
    165 % } elsif ($col->{type} eq 'status') {
    166 % my $status_map = ref $col->{cases} eq 'ARRAY' ? $col->{cases} : $keeper->default_status();
    167 % my ($doc_status) = grep { $_->[0] eq $document->{$col->{attr}} } @$status_map;
    168 % $doc_status ||= [$document->{$col->{attr}}, 'Неизвестный'];
    169 <td nowrap><% $doc_status->[1].'('.$doc_status->[0].')' %>\
    170 % } else {
    171 <td><% defined($document->{$col->{attr}}) ? $document->{$col->{attr}} : '&nbsp;' %>\
    172 % }
    173 % }
    174 </td>
    175 %
    176 % } #- for @columns
    177 %
    178 </tr>
    179 % } #- foreach @documents
    180 </table>
    181 % if ( ref $filter eq 'HASH' ) {
    182 % while ( my ($key, $value) = each %$filter ) {
    183 % next if $key eq 's';
    184 <input type="hidden" name="<% $key %>" value="<% $value |h %>">
    185 % }
    186 % }
    187 % if ( $inline_status || $delete_status ) {
    188 <div style="text-align:right; padding:10px 0;">
    189 % if ( $inline_status ) {
    190 <input type="submit" name="update" value="Сохранить изменения" class="input_btn">
    191 % }
    192 % if ( $delete_status ) {
    193 <input type="submit" name="delete" value="Удалить выбранные" class="input_btn" onclick="return confirm('Все отмеченные позиции будут удалены');">
    194 % }
    195 </div>
    196 % }
    197 </form>
    198 <%args>
    199
    200 $section => undef
    201 $documents => undef
    202 $columns => undef
    203 $id => undef
    204 $filter => undef
    205 $status => undef
    206
    207 </%args>
    208 <%init>
    209
    210 return unless ref $documents eq 'ARRAY';
    211 return unless ref $columns eq 'ARRAY';
    212
    213 @$columns = grep { $_->{attr} ne 'status' } @$columns;
    214 my $toopi = $project->documents();
    215 my $inline_status = 0;
    216 my $delete_status = 0;
    217 my $params = ref $filter eq 'HASH' ? join ('&', map { $_.'='.$filter->{$_} } keys %$filter ) : '';
    218 my $params_unclassed = ref $filter eq 'HASH' ? join ('&', map { $_.'='.$filter->{$_} } grep { $_ ne 'class' } keys %$filter ) : '';
    219 my $params_unsection = ref $filter eq 'HASH' ? join ('&', map { $_.'='.$filter->{$_} } grep { $_ ne 's' } keys %$filter ) : '';
    220
    221 my $active_rights = $m->comp('/contenido/webshop/subs/user_rights.msn');
    222
    223 my %users;
    224 my ($href, @actions, $user_id);
    225 if ( $status == 1 && (!$active_rights || $active_rights == 1) ) {
    226 $href = 'take_care.html';
    227 @actions = { href => $href, name => 'обработать' };
    228 $user_id = 'manager_id';
    229 } elsif ( $status == 2 && (!$active_rights || $active_rights == 2) ) {
    230 $href = 'facility.html';
    231 @actions = { href => $href, name => 'собрать' };
    232 $user_id = 'vault_id';
    233 } elsif ( $status == 3 && (!$active_rights || $active_rights == 3) ) {
    234 $href = 'delivery.html';
    235 @actions = { href => $href, name => 'доставить' };
    236 $user_id = 'postman_id';
    237 } elsif ( $status == 4 && !$active_rights ) {
    238 $href = 'delivery.html';
    239 @actions = { href => $href, name => 'просмотр' };
    240 }
    241
    242 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/components/order_form.msn

     
    1 <!-- Форма для редактирования объекта -->
    2 <a name="top"></a>
    3 % if ( $context eq 'facil' ) {
    4 <b style="font-size:110%">Комплектация ЗАКАЗА</b>
    5 % } elsif ( $context eq 'post' ) {
    6 <b style="font-size:110%">Доставка ЗАКАЗА</b>
    7 % } else {
    8 <b style="font-size:110%">Просмотр и редактирование ЗАКАЗА</b>
    9 % }
    10 <center>
    11 <table width="100%" cellpadding="0" cellspacing="0" border="0">
    12 <tr>
    13 <td bgcolor="#999999">
    14
    15
    16 <table width="100%" cellpadding="0" cellspacing="1" border="0">
    17 <tr><td valign="top" width="50%" bgcolor="#ffffff">
    18
    19 <form enctype="multipart/form-data" action="<% $action %>" method="POST" name="form" onSubmit="javascript:Save()">
    20
    21 <table border="0" width="100%" cellspacing="0" cellpadding="6">
    22 <tr>
    23 <td align="right">
    24 <input type="submit" value="Сохранить" class="input_btn">
    25 <input type="submit" name="_save_and_leave" value="Сохранить и выйти" class="input_btn">
    26 <input type="submit" name="delete" value="Отменить" onClick="return confirm('Отменить заказ?');" class="input_btn"><br>
    27 % if ( $context eq 'facil' ) {
    28 <input type="submit" name="_ret_manager" value="Вернуть менеджеру" class="input_btn">
    29 <input type="submit" name="_save_and_deliver" value="Отправить в доставку" class="input_btn">
    30 % } elsif ( $context eq 'post' ) {
    31 <input type="submit" name="_ret_manager" value="Вернуть менеджеру" class="input_btn">
    32 <input type="submit" name="_ret_facility" value="Вернуть в доставку" class="input_btn">
    33 <input type="submit" name="_save_and_deliver" value="Отметка о доставке" class="input_btn">
    34 % } else {
    35 <input type="submit" name="_save_and_complect" value="На комплектацию" class="input_btn">
    36 <input type="submit" name="_save_and_deliver" value="Сразу в доставку" class="input_btn">
    37 % }
    38
    39 <input type="hidden" name="control_charset" value="Контроль">
    40 % if ( ref $filter_params eq 'HASH' ) {
    41 % while ( my ($key, $value) = each %$filter_params ) {
    42 % next if grep { $_->{attr} eq $key } $object->structure();
    43 <input type="hidden" name="<% $key %>" value="<% $value %>">
    44 % }
    45 % }
    46 </td>
    47 </tr>
    48 </table>
    49
    50 <center>
    51 <table width="98%" cellpadding="1" cellspacing="0" border="0">
    52
    53 <%perl>
    54
    55 my @properties = $object->structure();
    56
    57 for (0..$#properties)
    58 {
    59
    60 my $prop = $properties[$_];
    61 my $field = $prop->{attr};
    62 next if ($prop->{hidden} == 1) || ($prop->{type} eq 'external');
    63 if ( $context eq 'facil' ) {
    64 next unless $prop->{$context.'show'} || $prop->{$context."edit"};
    65 } elsif ( $context eq 'post' ) {
    66 next unless $prop->{$context.'show'} || $prop->{$context."edit"};
    67 } else {
    68 next if $prop->{manager_hidden};
    69 }
    70
    71 </%perl>
    72 <tr><td height="8"></td></tr>
    73 <tr><td nowrap>
    74 <table cellpadding="0" cellspacing="0" border="0">
    75 <tr>
    76 % if( ( $prop->{type} eq 'flag' ) || ($prop->{type} eq 'checkbox') ) {
    77 <td><& "/contenido/components/inputs/checkbox.msn", prop => $prop, object=>$object, options=>$options, name => $prop->{attr}, check => $object->{$prop->{attr}}, id => $object->id() &></td>
    78 % }
    79 <td nowrap><b><% $prop->{rusname} %></b>&nbsp;/</td>
    80 <td align="right" nowrap><font color="#888888" size="-1">&nbsp;name="<% $prop->{attr} %>"</font></td>
    81 % if( $prop->{readonly} ) {
    82 <td align="right" nowrap>&nbsp;/&nbsp;<font color="#CC0000" size="-1">Значение нельзя изменить</font></td>
    83 % }
    84 </tr>
    85 </table>
    86 </td></tr>
    87 % if ( ($context && $prop->{$context.'show'}) || $prop->{manshow} ) {
    88 % if ( exists $prop->{lookup_opts} ) {
    89 % my $doc = $keeper->get_document_by_id( $object->$field, class => $prop->{lookup_opts}{class} );
    90 <tr><td><% $doc->name %></td></tr>
    91 % } elsif ( $prop->{type} eq 'status' ) {
    92 % my ($case) = grep { $_->[0] == $object->$field } @{$prop->{cases}};
    93 <tr><td><% ref $case ? $case->[1] : '<span style="color:red;">Значение: '.$object->$field.'</span>' %></td></tr>
    94 % } else {
    95 <tr><td><% $object->$field %></td></tr>
    96 % }
    97 % } else {
    98 % if ($prop->{type} eq 'parent') {
    99 <tr><td><& "/contenido/components/inputs/$prop->{type}.msn", prop => $prop, object=>$object, options=>$options, name => $prop->{attr}, check => ($object->{$prop->{attr} } || $prop->{default} || $sect_id ), id => $object->id() &></td></tr>
    100 % } elsif( ( $prop->{type} ne 'flag' ) && ($prop->{type} ne 'checkbox') ) {
    101 <tr><td><& "/contenido/components/inputs/$prop->{type}.msn", prop => $prop, object=>$object, options => $options, name => $prop->{attr}, check => $object->{$prop->{attr}}, id => ($object->id() || 0) &></td></tr>
    102 % }
    103 % }
    104 % }
    105 <tr>
    106 <td><br>
    107
    108 % for (0..$#properties) {
    109 % my $prop = $properties[$_];
    110 % next if ($prop->{hidden} != 1);
    111 <input type="hidden" name="<% $prop->{attr} %>" value="<% html_escape($object->{ $prop->{attr} }) %>">
    112 % }
    113 <input type="hidden" name="sect_id" value="<% $sect_id %>">
    114 %#если класса в свойствах обьекта нет все равно надо его пробросить как hidden
    115 % unless (grep {$_->{attr} eq 'class'} @properties) {
    116 <input type="hidden" name="class" value="<% html_escape($object->{class}) %>">
    117 % }
    118 <input type="hidden" name="save" value="1">
    119
    120 </td>
    121 </tr>
    122 </table>
    123 </center>
    124
    125 </form>
    126
    127 </td>
    128 <td valign="top" bgcolor="white" width="50%">
    129 <% spacer(w=>270) %>
    130 <div><iframe name="DocFinder" id="DocFinder" src="/contenido/find_document.html" frameborder="0"
    131 marginheight="0" marginwidth="0" width="100%" height="0"></iframe></div>
    132 <table width="100%" cellpadding="5" cellspacing="0" border="0"><tr><td>
    133 <p><font size=+1><b><nobr>Список позиций в заказе:</nobr></b></font></p>
    134
    135
    136 <& /contenido/webshop/components/order_list.msn, order => $object, filter_params => $filter_params, context => $context &>
    137
    138
    139
    140 </table>
    141 </td></tr></table>
    142
    143
    144 </td></tr>
    145 </table>
    146
    147 </td></tr></table>
    148 </center>
    149
    150 <script>
    151 <!--
    152 function updateList(theFild,value,text) {
    153 for (var i = 0; i < theFild.options.length; i++) {
    154 if (theFild.options[i].value == value) {
    155 return false;
    156 }
    157 }
    158 var option_length = theFild.options.length++;
    159 eval("theFild.options[option_length].value=value");
    160 eval("theFild.options[option_length].text=text");
    161
    162 Save(); this.form.submit();
    163
    164 }
    165 //-->
    166 </script>
    167
    168
    169 <%ARGS>
    170
    171 $proto => 'documents'
    172 $object => undef
    173 $context => undef
    174 $sect_id => 1
    175 $filter_params => undef
    176
    177 </%ARGS>
    178
    179 <%ONCE>
    180 my $PROTOS = {
    181 'documents' => ['документа','document.html','документу','документе'],
    182 'sections' => ['секции','section.html','секции','секции'],
    183 'links' => ['связи','link.html','связи','связи'],
    184 'users' => ['пользователя','users.html','пользователю','пользователе'],
    185 };
    186 </%ONCE>
    187
    188 <%INIT>
    189 return undef unless ref($object);
    190
    191 my $action = $context eq 'facil' ? 'facility.html' : $context eq 'post' ? 'delivery.html' : 'take_care.html';
    192 my $toopi = $project->$proto();
    193 my $options = {};
    194 if ($toopi && (ref($toopi) eq 'HASH') && (exists($toopi->{ $object->class }))) {
    195 %{ $options } = %{ $toopi->{ $object->class } };
    196 }
    197 </%INIT>
  • utf8/plugins/webshop/comps/contenido/webshop/components/order_list.msn

     
    1 <style>
    2
    3 .number { text-align:right; padding-right:5px; }
    4 .blue { color:blue; }
    5 input.text { border:1px solid gray; }
    6
    7 </style>
    8 % if ( @basket ) {
    9 <form action="recount.html" method="post">
    10 <table width="100%" border="0" cellpadding="4" cellspacing="0" class="tlistdocs" bgcolor="white">
    11 <tr bgcolor="#efefef">
    12 <th><% $context ? '&nbsp;' : '<img src="/contenido/i/actions/delete.gif">' %></th>
    13 <th>Артикул</th>
    14 <th>Название</th>
    15 <th>Цвет</th>
    16 <th>Цена</th>
    17 <th>Кол-во</th>
    18 <th>Сумма</th>
    19 </tr>
    20
    21 % foreach my $obj ( @basket ) {
    22 % $total_num += $obj->number;
    23 % $total_sum += $obj->number * $obj->price;
    24 <tr><td>\
    25 % if ( $context ) {
    26 &nbsp;\
    27 % } else {
    28 <input type="checkbox" name="delete" value="<% $obj->id %>">\
    29 % }
    30 </td>
    31 <td><% $obj->articul %></td>
    32 <td><% $obj->name %></td>
    33 <td><% $obj->colour %></td>
    34 % if ( $context ) {
    35 <td class="number"><% $obj->price %></td>
    36 <td class="number"><% $obj->number %></td>
    37 % } else {
    38 <td class="number"><input type="text" class="text number" size="8" name="item_<% $obj->id %>.price" value="<% $obj->price %>"></td>
    39 <td class="number"><input type="text" class="text number" size="5" name="item_<% $obj->id %>.num" value="<% $obj->number %>"></td>
    40 % }
    41 <td class="number"><% $obj->number * $obj->price %></td>
    42 </tr>
    43 % }
    44
    45 <tr>
    46 <td colspan="5" align="right"><b>Итого товаров</b></td>
    47 <td class="number"><b class="blue"><% $total_num %></b></td>
    48 <td class="number"><b class="blue"><% $total_sum %></b></td>
    49 </tr>
    50 <tr>
    51 <td colspan="5" align="right"><b>Доставка</b></td>
    52 <td class="number" colspan="2"><b class="blue"><% $order->sum_delivery %></b></td>
    53 </tr>
    54 <tr>
    55 <td colspan="5" align="right"><b>Итого с доставкой</b></td>
    56 <td class="number" colspan="2"><b class="blue"><% $total_sum + ($order->sum_delivery || 0) %></b></td>
    57 </tr>
    58
    59 </table>
    60 % unless ( $context ) {
    61 <div class="number"><input type="submit" name="update" value="Пересчитать" class="input_btn"></div>
    62 % }
    63 % if ( ref $filter_params eq 'HASH' ) {
    64 % while ( my ($key, $value) = each %$filter_params ) {
    65 % next if grep { $_->{attr} eq $key } $order->structure();
    66 <input type="hidden" name="<% $key %>" value="<% $value %>">
    67 % }
    68 % }
    69 <input type="hidden" name="id" value="<% $order->id %>">
    70
    71
    72 </form>
    73 % } else {
    74 <div style="color:red; font-size:110%; margin:20px 0;">Заказ пустой</div>
    75 % }
    76 <%args>
    77
    78 $order => undef
    79 $filter_params => undef
    80 $context => undef
    81
    82 </%args>
    83 <%init>
    84
    85 return unless ref $order;
    86 my @basket = $keeper->get_documents(
    87 class => 'webshop::Basket',
    88 status => 1,
    89 order_id => $order->id,
    90 );
    91 my $total_sum = 0;
    92 my $total_num = 0;
    93
    94 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/components/set_properties.msn

     
    1 <%ARGS>
    2
    3 $object => undef
    4 $SETS => undef
    5 $context=> undef
    6
    7 </%ARGS>
    8 <%INIT>
    9
    10 use Contenido::File;
    11 use vars qw($keeper $request );
    12
    13 $request->{local_codepage} = 'UTF8';
    14 $request->{local_codepage} = 'WIN' if Convert::Cyrillic::cstocs('WIN', 'UTF8', $SETS->{control_charset}) eq 'Контроль';
    15 $request->{local_codepage} = 'KOI8' if Convert::Cyrillic::cstocs('KOI8', 'UTF8', $SETS->{control_charset}) eq 'Контроль';
    16
    17 warn "Contenido Debug: Форма для редактирования пришла в кодировке ".$request->{local_codepage}."\n" if ($state->debug());
    18
    19 my @properties = $object->structure();
    20 for (0..$#properties)
    21 {
    22 my $prop = $properties[$_];
    23 my $name = $prop->{attr};
    24 my $type = $prop->{type};
    25
    26 next if ($name eq 'sections');
    27 next if ($name eq 'id');
    28
    29 next if $prop->{hidden};
    30 next if $context =~ /(facil|post)/ && $prop->{$context.'show'};
    31 next if !$context && ($prop->{manshow} || $prop->{manager_hidden});
    32
    33 if ( exists $SETS->{$name} ) {
    34 if ($m->comp_exists("/contenido/components/outputs/$type.msn")) {
    35 $object->{$name} = $m->comp("/contenido/components/outputs/$type.msn", SETS => $SETS, name => $name, object => $object );
    36 } else {
    37 $object->{$name} = $m->comp('/contenido/components/filter.msn', str => $SETS->{$name} );
    38 }
    39 }
    40
    41 }
    42
    43 # По идее - мы работаем с ссылкой, так что ничего не надо возвращать!
    44 # O-ле! О-ле! О-ле!
    45 return 1;
    46
    47 </%INIT>
  • utf8/plugins/webshop/comps/contenido/webshop/delivery.html

     
    1 %# vim:syn=mason
    2 <& "/contenido/components/header.msn" &>
    3 <& "/contenido/components/naviline.msn", sect_id => $owner->id &>
    4
    5 % if ($error) {
    6 <div align="center" style="font-size:110%; color:red;">
    7 <% $error %>
    8 </div>
    9 <br><br>
    10 % }
    11
    12 % if (!ref($document)) {
    13 % if ($id) {
    14 <div align="center" style="font-size:110%; color:red;">
    15 Документ с идентификатором <% $id %> не найден
    16 </div>
    17 <br><br>
    18 % } elsif ($class) {
    19 <!-- Блок с выбором нового документа для создания -->
    20 <table width="50%" border="0"><tr><td>
    21 <fieldset>
    22 <legend>Выберите тип документа для создания</legend>
    23 <& "/contenido/components/new_objects_form.msn", proto => 'documents', sect_id => $owner->id &>
    24 </fieldset>
    25 </td></tr></table>
    26 % } else {
    27 <div align="center" style="font-size:110%; color:red;">
    28 Неверный вызов документа!!! (отсутствуют id и class одновременно)
    29 </div>
    30 <br><br>
    31 % }
    32
    33 % } else {
    34 % if ( $document->postman_id == $user->id ) {
    35 <& "/contenido/components/obj_list_js.msn", object => $document &>
    36 <& "/contenido/webshop/components/order_form.msn",
    37 context => 'post',
    38 object => $document,
    39 proto => 'documents',
    40 sect_id => $owner->id,
    41 clone => $clone,
    42 filter_params => \%filter_params,
    43 &>
    44 % } else {
    45 % my $profile = $keeper->get_user_by_id( $document->postman_id );
    46 <div style="padding:10px;">
    47 <b style="font-size:110%">Доставка ЗАКАЗА</b>
    48 <p style="color:red"><b>Внимание!</b> Доставку заказа осуществляет <% $profile->name %></p>
    49 <p><a href="./?ost=3">&lt;&lt; Вернуться в список доставки</a></p>
    50 </div>
    51 % }
    52 % }
    53
    54 </body>
    55 </html>
    56 <%ARGS>
    57 $p => 1
    58 $class => 'webshop::Order'
    59 $sect_id => undef
    60 $s_alias => undef
    61 $id => undef
    62 $delete => undef
    63 $save => undef
    64 $clone => undef
    65 $activate => undef
    66 $deactivate => undef
    67 </%ARGS>
    68 <%INIT>
    69
    70 &abort404 unless $class;
    71 my $error='';
    72 ### !!! При добавлении переменных в ARGS их надо внести в список исключений в структуре ниже
    73
    74 my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
    75
    76 my $document;
    77 my $new;
    78 my $now = Contenido::DateTime->new;
    79
    80 if ($id && ($id !~ /\D/) && ($id > 0)) {
    81 $document = $keeper->get_document_by_id($id, class=>$class);
    82 if ( $clone && exists $document->{'attributes'}->{'dtime'} ) {
    83 $document->dtime(undef);
    84 }
    85 } elsif ( ($class) && (length($class)>0) && (! ref($document)) ) {
    86 $document = new $class ($keeper);
    87 $new = 1;
    88 my @properties = $document->structure();
    89 foreach my $prop ( @properties ) {
    90 my $attr = $prop->{attr};
    91 ### !!! Если не стандартная переменная, то можем инициализировать
    92 if ( exists $ARGS{$attr} && ! grep { $prop->{attr} eq $_ } qw( class sect_id id delete save clone s_alias activate deactivate p s use_section alpha alpha_search search_by search ) ) {
    93 $document->$attr($ARGS{$attr});
    94 }
    95 }
    96 }
    97 &abort404 unless ref $document;
    98
    99 my @props = $document->structure();
    100 my %filter_params;
    101 if ($ARGS{use_section} && !grep { $_->{attr} eq 'use_section' } @props ) {
    102 $filter_params{use_section} = $ARGS{use_section};
    103 $filter_params{class} = $document->class;
    104 }
    105 $filter_params{alpha} = $ARGS{alpha} if $ARGS{alpha} && !grep { $_->{attr} eq 'alpha' } @props;
    106 $filter_params{alpha_search} = $ARGS{alpha_search} if $ARGS{alpha_search} && !grep { $_->{attr} eq 'alpha_search' } @props;
    107 $filter_params{search_by} = $ARGS{search_by} if $ARGS{search_by} && !grep { $_->{attr} eq 'search_by' } @props;
    108 $filter_params{search} = $ARGS{search} if $ARGS{search} && !grep { $_->{attr} eq 'search' } @props;
    109 $filter_params{s} = $ARGS{s} if $ARGS{s} && !grep { $_->{attr} eq 's' } @props;
    110 $filter_params{p} = $p if $p > 1;
    111 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
    112
    113
    114 if ($s_alias) {
    115 $sect_id = $project->s_alias->{$s_alias};
    116 }
    117
    118 if ( (! $sect_id) && (ref($document)) && ($document->id) ) {
    119 $sect_id = $document->section();
    120 }
    121 my $owner = $keeper->get_section_by_id ($sect_id || $Contenido::Section::ROOT || 1);
    122
    123 if (! ref($owner)) {
    124 $owner = $keeper->get_section_by_id ($Contenido::Section::ROOT || 1);
    125 }
    126 if (! ref($owner)) {
    127 warn "Contenido Die: Не могу найти корневую секцию\n";
    128 return undef;
    129 }
    130
    131 if ( ref $document && !$document->postman_id ) {
    132 $document->postman_id( $user->id );
    133 $document->store;
    134 }
    135 if (ref($document) && $document->id() && $document->section()) {
    136 my $document_access = $user->section_accesses($user, $owner);
    137 if ($document_access != 2) {
    138 $m->clear_buffer;
    139 $m->abort(403);
    140 }
    141 }
    142
    143 # Удаление...
    144 if (defined($id) && ($id > 0) && $delete) {
    145 $document->status( 5 );
    146 $document->store;
    147
    148 $m->redirect("./?ost=3".($return_params ? '&'.$return_params : ''));
    149 }
    150
    151 # Сохранение существующего документа или создание нового...
    152 # Кстати, пока никак не обрабатываются связи...
    153 elsif ( $save == 1 )
    154 {
    155 my $clonesource;
    156 if ( $clone ) {
    157 $clonesource = $keeper->get_document_by_id ($clone,
    158 class => $document->class,
    159 );
    160 }
    161 if ($m->comp('/contenido/webshop/components/set_properties.msn', object => $document, SETS => \%ARGS, context => 'post') != 1)
    162 {
    163 # Ошибка, надо бы обработать...
    164 warn "Contenido Warning: Не могу установить значения полей!\n";
    165 }
    166 if ( $clone ) {
    167 $m->comp('/contenido/components/clone_attachments.msn', object => $document, source => $clonesource );
    168 $document->sections( $clonesource->sections );
    169 } elsif ( $new ) {
    170 $document->sections( $owner->id, $filter > 0 ? ($filter) : ());
    171 }
    172
    173 if ( $ARGS{_save_and_deliver} ) {
    174 $document->status(4);
    175 $document->postman_id( $user->id );
    176 $document->etime( $now->ymd('-').' '.$now->hms );
    177 } elsif ( $ARGS{_ret_manager} ) {
    178 $document->status(1);
    179 } elsif ( $ARGS{_ret_facility} ) {
    180 $document->status(2);
    181 } elsif ( $ARGS{_save_and_leave} ) {
    182 }
    183
    184 unless ($document->store()) {
    185 # Ошибка, надо бы обработать...
    186 $error="Ошибка сохранения ($keeper->{last_error})";
    187 } else {
    188
    189 if ($ARGS{_save_and_deliver}) {
    190 $m->redirect("./?ost=3");
    191 } elsif ($ARGS{_ret_manager}) {
    192 $m->redirect("./?ost=3");
    193 } elsif ($ARGS{_ret_facility}) {
    194 $m->redirect("./?ost=3");
    195 } elsif ($ARGS{_save_and_leave}) {
    196 $m->redirect("./?ost=1".($return_params ? '&'.$return_params : ''));
    197 }
    198
    199 $m->redirect("delivery.html?id=".$document->id.($return_params ? '&'.$return_params : ''));
    200 }
    201 }
    202
    203 </%INIT>
  • utf8/plugins/webshop/comps/contenido/webshop/dhandler

     
    1 <& $call, %ARGS &>
    2 <%init>
    3
    4 my $call;
    5 if ( $r->uri eq '/contenido/webshop/' ) {
    6 $call = 'index.html';
    7 } else {
    8 &abort404;
    9 }
    10
    11 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/facility.html

     
    1 %# vim:syn=mason
    2 <& "/contenido/components/header.msn" &>
    3 <& "/contenido/components/naviline.msn", sect_id => $owner->id &>
    4
    5 % if ($error) {
    6 <div align="center" style="font-size:110%; color:red;">
    7 <% $error %>
    8 </div>
    9 <br><br>
    10 % }
    11
    12 % if (!ref($document)) {
    13 % if ($id) {
    14 <div align="center" style="font-size:110%; color:red;">
    15 Документ с идентификатором <% $id %> не найден
    16 </div>
    17 <br><br>
    18 % } elsif ($class) {
    19 <!-- Блок с выбором нового документа для создания -->
    20 <table width="50%" border="0"><tr><td>
    21 <fieldset>
    22 <legend>Выберите тип документа для создания</legend>
    23 <& "/contenido/components/new_objects_form.msn", proto => 'documents', sect_id => $owner->id &>
    24 </fieldset>
    25 </td></tr></table>
    26 % } else {
    27 <div align="center" style="font-size:110%; color:red;">
    28 Неверный вызов документа!!! (отсутствуют id и class одновременно)
    29 </div>
    30 <br><br>
    31 % }
    32
    33 % } else {
    34
    35 % if ( $document->vault_id == $user->id ) {
    36 <& "/contenido/components/obj_list_js.msn", object => $document &>
    37 <& "/contenido/webshop/components/order_form.msn",
    38 context => 'facil',
    39 object => $document,
    40 proto => 'documents',
    41 sect_id => $owner->id,
    42 clone => $clone,
    43 filter_params => \%filter_params,
    44 &>
    45 % } else {
    46 % my $profile = $keeper->get_user_by_id( $document->vault_id );
    47 <div style="padding:10px;">
    48 <b style="font-size:110%">Комплектация ЗАКАЗА</b>
    49 <p style="color:red"><b>Внимание!</b> Комплектацией заказа занимается <% $profile->name %></p>
    50 <p><a href="./?ost=2">&lt;&lt; Вернуться в список комплектации</a></p>
    51 </div>
    52 % }
    53 % }
    54
    55 </body>
    56 </html>
    57 <%ARGS>
    58 $p => 1
    59 $class => 'webshop::Order'
    60 $sect_id => undef
    61 $s_alias => undef
    62 $id => undef
    63 $delete => undef
    64 $save => undef
    65 $clone => undef
    66 $activate => undef
    67 $deactivate => undef
    68 </%ARGS>
    69 <%INIT>
    70
    71 &abort404 unless $class;
    72 my $error='';
    73 ### !!! При добавлении переменных в ARGS их надо внести в список исключений в структуре ниже
    74
    75 my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
    76
    77 my $document;
    78 my $new;
    79 my $now = Contenido::DateTime->new;
    80
    81 if ($id && ($id !~ /\D/) && ($id > 0)) {
    82 $document = $keeper->get_document_by_id($id, class=>$class);
    83 if ( $clone && exists $document->{'attributes'}->{'dtime'} ) {
    84 $document->dtime(undef);
    85 }
    86 } elsif ( ($class) && (length($class)>0) && (! ref($document)) ) {
    87 $document = new $class ($keeper);
    88 $new = 1;
    89 my @properties = $document->structure();
    90 foreach my $prop ( @properties ) {
    91 my $attr = $prop->{attr};
    92 ### !!! Если не стандартная переменная, то можем инициализировать
    93 if ( exists $ARGS{$attr} && ! grep { $prop->{attr} eq $_ } qw( class sect_id id delete save clone s_alias activate deactivate p s use_section alpha alpha_search search_by search ) ) {
    94 $document->$attr($ARGS{$attr});
    95 }
    96 }
    97 }
    98 &abort404 unless ref $document;
    99
    100 my @props = $document->structure();
    101 my %filter_params;
    102 if ($ARGS{use_section} && !grep { $_->{attr} eq 'use_section' } @props ) {
    103 $filter_params{use_section} = $ARGS{use_section};
    104 $filter_params{class} = $document->class;
    105 }
    106 $filter_params{alpha} = $ARGS{alpha} if $ARGS{alpha} && !grep { $_->{attr} eq 'alpha' } @props;
    107 $filter_params{alpha_search} = $ARGS{alpha_search} if $ARGS{alpha_search} && !grep { $_->{attr} eq 'alpha_search' } @props;
    108 $filter_params{search_by} = $ARGS{search_by} if $ARGS{search_by} && !grep { $_->{attr} eq 'search_by' } @props;
    109 $filter_params{search} = $ARGS{search} if $ARGS{search} && !grep { $_->{attr} eq 'search' } @props;
    110 $filter_params{s} = $ARGS{s} if $ARGS{s} && !grep { $_->{attr} eq 's' } @props;
    111 $filter_params{p} = $p if $p > 1;
    112 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
    113
    114
    115 if ($s_alias) {
    116 $sect_id = $project->s_alias->{$s_alias};
    117 }
    118
    119 if ( (! $sect_id) && (ref($document)) && ($document->id) ) {
    120 $sect_id = $document->section();
    121 }
    122 my $owner = $keeper->get_section_by_id ($sect_id || $Contenido::Section::ROOT || 1);
    123
    124 if (! ref($owner)) {
    125 $owner = $keeper->get_section_by_id ($Contenido::Section::ROOT || 1);
    126 }
    127 if (! ref($owner)) {
    128 warn "Contenido Die: Не могу найти корневую секцию\n";
    129 return undef;
    130 }
    131
    132 if ( ref $document ) {
    133 $document->vault_id( $user->id );
    134 $document->store;
    135 }
    136 if (ref($document) && $document->id() && $document->section()) {
    137 my $document_access = $user->section_accesses($user, $owner);
    138 if ($document_access != 2) {
    139 $m->clear_buffer;
    140 $m->abort(403);
    141 }
    142 }
    143
    144 # Удаление...
    145 if (defined($id) && ($id > 0) && $delete) {
    146 $document->status( 5 );
    147 $document->store;
    148
    149 $m->redirect("./?ost=2".($return_params ? '&'.$return_params : ''));
    150 }
    151
    152 # Сохранение существующего документа или создание нового...
    153 # Кстати, пока никак не обрабатываются связи...
    154 elsif ( $save == 1 )
    155 {
    156 if ($m->comp('/contenido/webshop/components/set_properties.msn', object => $document, SETS => \%ARGS, context => 'facil') != 1)
    157 {
    158 # Ошибка, надо бы обработать...
    159 warn "Contenido Warning: Не могу установить значения полей!\n";
    160 }
    161
    162 if ( $ARGS{_save_and_deliver} ) {
    163 $document->vault_id( $user->id );
    164 $document->ftime( $now->ymd('-').' '.$now->hms );
    165 $document->status(3);
    166 } elsif ( $ARGS{_ret_manager} ) {
    167 $document->status(1);
    168 } elsif ( $ARGS{_save_and_leave} ) {
    169 $document->vault_id( undef );
    170 $document->status(1);
    171 }
    172
    173 unless ($document->store()) {
    174 # Ошибка, надо бы обработать...
    175 $error="Ошибка сохранения ($keeper->{last_error})";
    176 } else {
    177
    178 if ($ARGS{_save_and_deliver}) {
    179 $m->redirect("./?ost=3");
    180 } elsif ($ARGS{_ret_manager}) {
    181 $m->redirect("./?ost=2");
    182 } elsif ($ARGS{_save_and_leave}) {
    183 $m->redirect("./?ost=2");
    184 } elsif ($ARGS{_save_and_leave}) {
    185 $m->redirect("./?ost=1".($return_params ? '&'.$return_params : ''));
    186 }
    187
    188 $m->redirect("take_care.html?id=".$document->id.($return_params ? '&'.$return_params : ''));
    189 }
    190 }
    191
    192 </%INIT>
  • utf8/plugins/webshop/comps/contenido/webshop/index.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 <table width="100%" cellspacing="0" cellpadding="0" border="0">
    11 <tr valign="top">
    12 <td width="35%">
    13
    14 <& /contenido/webshop/components/block_order_status_changer.msn, status => $ost &>
    15
    16 </td>
    17 <td width="1%">&nbsp;</td>
    18 <td width="65%">
    19
    20 <fieldset>
    21 <legend>Заказы со статусом "<span style="color:yellow"><% $current_status->[1] %></span>"</legend>
    22
    23 % if ( $total ) {
    24
    25 <div style="font-size:75%; font-family:Arial;">
    26 <& /inc/pages_.msn, p=>$p, n=>$size, total=>$total, params=>\%filter_params, &>
    27 <div style="height:5px"><spacer type="block" height="5"></div>
    28 </div>
    29
    30 <& /contenido/webshop/components/order_browse.msn, documents => \@documents, columns => \@columns, filter => \%filter_params, status => $ost, %ARGS &>
    31
    32 <div style="font-size:75%; font-family:Arial;">
    33 <& /inc/pages_.msn, p=>$p, n=>$size, total=>$total, params=>\%filter_params, &>
    34 <div style="height:5px"><spacer type="block" height="5"></div>
    35 </div>
    36
    37 % } else {
    38 <h4 align="center"><i>---- Нет документов -----</i></h4>
    39 % }
    40
    41
    42 </td>
    43 <td width="1%">&nbsp;</td>
    44 </tr>
    45 </table>
    46
    47 </body>
    48 </html>
    49 <%args>
    50
    51 $ost => 1
    52 $p => 1
    53
    54 </%args>
    55 <%init>
    56
    57 my %filter_params;
    58
    59 my (@documents, $total);
    60 $filter_params{ost} = $ost if $ost != 1;
    61 my $size = 40;
    62
    63 @documents = $keeper->get_documents(
    64 class => 'webshop::Order',
    65 status => $ost,
    66 limit => $size,
    67 offset => ($p-1)*$size,
    68 );
    69 $total = $keeper->get_documents(
    70 class => 'webshop::Order',
    71 status => $ost,
    72 count => 1,
    73 );
    74 my @structure = webshop::Order->new( $keeper->{webshop} )->structure;
    75 my @columns = sort { $a->{column} <=> $b->{column} }
    76 grep { $_->{column} } @structure;
    77 push @columns, {attr => '_act_', rusname => 'Действия'};
    78 my ($status_map) = grep { $_->{attr} eq 'status' } @structure;
    79 my ($current_status) = grep { $_->[0] == $ost } @{$status_map->{cases}};
    80
    81 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/recount.html

     
    1 <pre><% Dumper(\%ARGS) %></pre>
    2 <%args>
    3
    4 $delete => []
    5 $update => undef
    6 $id => undef
    7
    8 </%args>
    9 <%init>
    10
    11 &abort404 unless $id && $id =~ /^\d+$/;
    12
    13 my $order = $keeper->{webshop}->get_orders( id => $id );
    14 &abort404 unless ref $order;
    15
    16 if ( $update ) {
    17 my @delete = ref $delete ? @$delete : ();
    18 my (%renumber, %reprice);
    19 while ( my ($key, $value) = each %ARGS ) {
    20 if ( $key =~ /item_(\d+)\.num/ ) {
    21 my $id = $1;
    22 $renumber{$id} = $value if $value =~ /^\d+$/;
    23 } elsif ( $key =~ /item_(\d+)\.price/ ) {
    24 my $id = $1;
    25 $reprice{$id} = $value if $value =~ /^[\d\.]+$/;
    26 }
    27 }
    28 my ($total, $sum, $new_basket) = $keeper->{webshop}->recount(
    29 order_id=> $order->id,
    30 delete => \@delete,
    31 price => \%reprice,
    32 session_no_store=>1,
    33 renumber => \%renumber,
    34 );
    35 $order->total( $total );
    36 $order->sum( $sum );
    37 $order->store;
    38 $m->redirect('/contenido/webshop/take_care.html?id='.$id);
    39 }
    40
    41 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/subs/user_rights.msn

     
    1 <%init>
    2
    3 if ( grep { $_->{attr} eq 'type' } $user->structure ) {
    4 return $user->type;
    5 } else {
    6 return 0;
    7 }
    8
    9 </%init>
  • utf8/plugins/webshop/comps/contenido/webshop/take_care.html

     
    1 %# vim:syn=mason
    2 <& "/contenido/components/header.msn" &>
    3 <& "/contenido/components/naviline.msn", sect_id => $owner->id &>
    4
    5 % if ($error) {
    6 <div align="center" style="font-size:110%; color:red;">
    7 <% $error %>
    8 </div>
    9 <br><br>
    10 % }
    11
    12 % if (!ref($document)) {
    13 % if ($id) {
    14 <div align="center" style="font-size:110%; color:red;">
    15 Документ с идентификатором <% $id %> не найден
    16 </div>
    17 <br><br>
    18 % } elsif ($class) {
    19 <!-- Блок с выбором нового документа для создания -->
    20 <table width="50%" border="0"><tr><td>
    21 <fieldset>
    22 <legend>Выберите тип документа для создания</legend>
    23 <& "/contenido/components/new_objects_form.msn", proto => 'documents', sect_id => $owner->id &>
    24 </fieldset>
    25 </td></tr></table>
    26 % } else {
    27 <div align="center" style="font-size:110%; color:red;">
    28 Неверный вызов документа!!! (отсутствуют id и class одновременно)
    29 </div>
    30 <br><br>
    31 % }
    32
    33 % } else {
    34
    35 <& "/contenido/components/obj_list_js.msn", object => $document &>
    36 <& "/contenido/webshop/components/order_form.msn",
    37 object => $document,
    38 proto => 'documents',
    39 sect_id => $owner->id,
    40 filter_params => \%filter_params,
    41 &>
    42 % }
    43
    44 </body>
    45 </html>
    46 <%ARGS>
    47 $p => 1
    48 $class => 'webshop::Order'
    49 $sect_id => undef
    50 $s_alias => undef
    51 $id => undef
    52 $delete => undef
    53 $save => undef
    54 </%ARGS>
    55 <%INIT>
    56
    57 &abort404 unless $class;
    58 my $error='';
    59 ### !!! При добавлении переменных в ARGS их надо внести в список исключений в структуре ниже
    60
    61 my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
    62
    63 my $document;
    64 my $new;
    65 my $now = Contenido::DateTime->new;
    66
    67 if ($id && ($id !~ /\D/) && ($id > 0)) {
    68 $document = $keeper->get_document_by_id($id, class=>$class);
    69 } elsif ( ($class) && (length($class)>0) && (! ref($document)) ) {
    70 $document = new $class ($keeper);
    71 $new = 1;
    72 my @properties = $document->structure();
    73 foreach my $prop ( @properties ) {
    74 my $attr = $prop->{attr};
    75 ### !!! Если не стандартная переменная, то можем инициализировать
    76 if ( exists $ARGS{$attr} && ! grep { $prop->{attr} eq $_ } qw( class sect_id id delete save s_alias p s use_section alpha alpha_search search_by search ) ) {
    77 $document->$attr($ARGS{$attr});
    78 }
    79 }
    80 }
    81 &abort404 unless ref $document;
    82
    83 my @props = $document->structure();
    84 my %filter_params;
    85 if ($ARGS{use_section} && !grep { $_->{attr} eq 'use_section' } @props ) {
    86 $filter_params{use_section} = $ARGS{use_section};
    87 $filter_params{class} = $document->class;
    88 }
    89 $filter_params{alpha} = $ARGS{alpha} if $ARGS{alpha} && !grep { $_->{attr} eq 'alpha' } @props;
    90 $filter_params{alpha_search} = $ARGS{alpha_search} if $ARGS{alpha_search} && !grep { $_->{attr} eq 'alpha_search' } @props;
    91 $filter_params{search_by} = $ARGS{search_by} if $ARGS{search_by} && !grep { $_->{attr} eq 'search_by' } @props;
    92 $filter_params{search} = $ARGS{search} if $ARGS{search} && !grep { $_->{attr} eq 'search' } @props;
    93 $filter_params{s} = $ARGS{s} if $ARGS{s} && !grep { $_->{attr} eq 's' } @props;
    94 $filter_params{p} = $p if $p > 1;
    95 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
    96
    97
    98 if ($s_alias) {
    99 $sect_id = $project->s_alias->{$s_alias};
    100 }
    101
    102 if ( (! $sect_id) && (ref($document)) && ($document->id) ) {
    103 $sect_id = $document->section();
    104 }
    105 my $owner = $keeper->get_section_by_id ($sect_id || $Contenido::Section::ROOT || 1);
    106
    107 if (! ref($owner)) {
    108 $owner = $keeper->get_section_by_id ($Contenido::Section::ROOT || 1);
    109 }
    110 if (! ref($owner)) {
    111 warn "Contenido Die: Не могу найти корневую секцию\n";
    112 return undef;
    113 }
    114
    115 if ( ref $document ) {
    116 $document->manager_id( $user->id );
    117 $document->store;
    118 }
    119 if (ref($document) && $document->id() && $document->section()) {
    120 my $document_access = $user->section_accesses($user, $owner);
    121 if ($document_access != 2) {
    122 $m->clear_buffer;
    123 $m->abort(403);
    124 }
    125 }
    126
    127 # Удаление...
    128 if (defined($id) && ($id > 0) && $delete) {
    129 $document->status( 5 );
    130 $document->store;
    131
    132 $m->redirect("./?ost=1".($return_params ? '&'.$return_params : ''));
    133 }
    134
    135 # Сохранение существующего документа или создание нового...
    136 # Кстати, пока никак не обрабатываются связи...
    137 elsif ( $save == 1 )
    138 {
    139 if ($m->comp('/contenido/webshop/components/set_properties.msn', object => $document, SETS => \%ARGS) != 1)
    140 {
    141 # Ошибка, надо бы обработать...
    142 warn "Contenido Warning: Не могу установить значения полей!\n";
    143 }
    144 if ( $new ) {
    145 $document->sections( $owner->id, $filter > 0 ? ($filter) : ());
    146 }
    147
    148 if ( $ARGS{_save_and_deliver} ) {
    149 $document->manager_id( $user->id );
    150 $document->ftime( $now->ymd('-').' '.$now->hms );
    151 $document->status(3);
    152 } elsif ( $ARGS{_save_and_complect} ) {
    153 $document->manager_id( $user->id );
    154 $document->btime( $now->ymd('-').' '.$now->hms );
    155 $document->status(2);
    156 } elsif ( $ARGS{_save_and_leave} ) {
    157 $document->manager_id( undef );
    158 $document->status(1);
    159 }
    160
    161 unless ($document->store()) {
    162 # Ошибка, надо бы обработать...
    163 $error="Ошибка сохранения ($keeper->{last_error})";
    164 } else {
    165
    166 if ($ARGS{_save_and_complect}) {
    167 $m->redirect("./?ost=2");
    168 } elsif ($ARGS{_save_and_deliver}) {
    169 $m->redirect("./?ost=3");
    170 } elsif ($ARGS{_save_and_leave}) {
    171 $m->redirect("./?ost=1".($return_params ? '&'.$return_params : ''));
    172 }
    173
    174 $m->redirect("take_care.html?id=".$document->id.($return_params ? '&'.$return_params : ''));
    175 }
    176 }
    177
    178 </%INIT>
  • utf8/plugins/webshop/config.proto

     
    1 #############################################################################
    2 #
    3 # Параметры данного шаблона необходимо ВРУЧНУЮ добавить в config.mk проекта
    4 # и привести в соответствие с требованиями проекта
    5 #
    6 #############################################################################
    7
    8 PLUGINS += webshop
    9
    10
    11 #############################################################################
    12 # Параметр испфльзуется для переопределения на уровне проекта таблицы или класса
    13 # для хранения описания товара
    14
    15 ITEM_DOCUMENT_CLASS = webshop::Item
    16 REWRITE += ITEM_DOCUMENT_CLASS
    17
    18 ITEM_DOCUMENT_TABLE = webshop::SQL::Items
    19 REWRITE += ITEM_DOCUMENT_TABLE
    20
  • utf8/plugins/webshop/lib/webshop/Address.pm

     
    1 package webshop::Address;
    2
    3 use Contenido::Globals;
    4 use base "Contenido::Document";
    5 sub extra_properties
    6 {
    7 return (
    8 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус заказа',
    9 'cases' => [
    10 [0, 'Дополнительный адрес'],
    11 [1, 'Основной адрес'],
    12 ],
    13 },
    14 { 'attr' => 'delivery', 'type' => 'lookup', 'rusname' => 'Тип доставки',
    15 'lookup_opts' => {
    16 'class' => 'webshop::Delivery',
    17 },
    18 },
    19 { 'attr' => 'name', 'type' => 'string', 'rusname' => 'Контактное лицо' },
    20 { 'attr' => 'phone', 'type' => 'string', 'rusname' => 'Телефон для связи' },
    21 { 'attr' => 'zipcode', 'type' => 'string', 'rusname' => 'Почтовый индекс' },
    22 { 'attr' => 'town', 'type' => 'string', 'rusname' => 'Город' },
    23 { 'attr' => 'metro', 'type' => 'string', 'rusname' => 'Ближайшее метро' },
    24 { 'attr' => 'address', 'type' => 'text', 'rusname' => 'Адрес доставки', rows => 5 },
    25 { 'attr' => 'timeline', 'type' => 'string', 'rusname' => 'Предпочтительное время' },
    26 { 'attr' => 'description', 'type' => 'text', 'rusname' => 'Описание для курьера', rows => 5 },
    27 )
    28 }
    29
    30 sub class_name
    31 {
    32 return 'Заказ';
    33 }
    34
    35 sub class_description
    36 {
    37 return 'Заказ';
    38 }
    39
    40 sub class_table
    41 {
    42 return 'webshop::SQL::AddressTable';
    43 }
    44
    45 1;
  • utf8/plugins/webshop/lib/webshop/Apache.pm

     
    1 package webshop::Apache;
    2
    3 use strict;
    4 use warnings 'all';
    5
    6 use webshop::State;
    7 use Contenido::Globals;
    8
    9
    10 sub child_init {
    11 # встраиваем keeper плагина в keeper проекта
    12 $keeper->{webshop} = webshop::Keeper->new($state->webshop);
    13 }
    14
    15 sub request_init {
    16 }
    17
    18 sub child_exit {
    19 }
    20
    21 1;
  • utf8/plugins/webshop/lib/webshop/Basket.pm

     
    1 package webshop::Basket;
    2
    3 use base "Contenido::Document";
    4 sub extra_properties
    5 {
    6 return (
    7 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус заказа',
    8 'cases' => [
    9 [0, 'Элемент wish-листа'],
    10 [1, 'Элемент корзины'],
    11 ],
    12 },
    13 { 'attr' => 'articul', 'type' => 'string', 'rusname' => 'Артикул' },
    14 { 'attr' => 'colour', 'type' => 'string', 'rusname' => 'Цвет' },
    15 { 'attr' => 'discount_flag', 'type' => 'string', 'rusname' => 'Наличие скидки' },
    16 { 'attr' => 'discount', 'type' => 'text', 'rusname' => 'Формула скидки', rows => 15 },
    17 )
    18 }
    19
    20 sub price_formatted {
    21 my $self = shift;
    22
    23 my $price = $self->price;
    24 $price = reverse $price;
    25 $price =~ s/(\d{3})/$1\ /g;
    26 $price = reverse $price;
    27
    28 return $price;
    29 }
    30
    31 sub total_formatted {
    32 my $self = shift;
    33
    34 my $price = $self->price * ($self->number || 0);
    35 $price = reverse $price;
    36 $price =~ s/(\d{3})/$1\ /g;
    37 $price = reverse $price;
    38
    39 return $price;
    40 }
    41
    42 sub class_name
    43 {
    44 return 'Позиция в корзине';
    45 }
    46
    47 sub class_description
    48 {
    49 return 'Позиция в корзине';
    50 }
    51
    52 sub class_table
    53 {
    54 return 'webshop::SQL::Basket';
    55 }
    56
    57 1;
  • utf8/plugins/webshop/lib/webshop/Delivery.pm

     
    1 package webshop::Delivery;
    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 { 'attr' => 'dtime', 'hidden' => 1 },
    14 { 'attr' => 'price', 'type' => 'string', 'rusname' => 'Стоимость доставки (NN или NN%)', default => 0 },
    15 { 'attr' => 'abstr', 'type' => 'text', 'rusname' => 'Краткое описание' },
    16 { 'attr' => 'fields', 'type' => 'status_multi', 'rusname' => 'Поля, необходимые к заполнению',
    17 'cases' => [
    18 ['timeline','Время заказа'],
    19 ['zipcode','Почтовый индекс'],
    20 ['town','Город'],
    21 ['address','Адрес'],
    22 ['metro','Ближайшее метро'],
    23 ],
    24 },
    25 )
    26 }
    27
    28 sub class_name
    29 {
    30 return 'Способ доставки';
    31 }
    32
    33 sub class_description
    34 {
    35 return 'Способ доставки';
    36 }
    37
    38 sub pre_store
    39 {
    40 my $self = shift;
    41
    42 my $default_section = $project->s_alias->{delivery} if ref $project->s_alias eq 'HASH';
    43 my $sections = $self->{sections};
    44 if ( $default_section ) {
    45 if ( ref $sections eq 'ARRAY' && scalar @$sections ) {
    46 my @new_sects = grep { $_ != $default_section } @$sections;
    47 push @new_sects, $default_section;
    48 $self->sections(@new_sects);
    49 } elsif ( $sections && !ref $sections && $sections != $default_section ) {
    50 my @new_sects = ($default_section, $sections);
    51 $self->sections(@new_sects);
    52 } else {
    53 $self->sections($default_section);
    54 }
    55 }
    56
    57 return 1;
    58 }
    59
    60 1;
  • utf8/plugins/webshop/lib/webshop/DeliverySection.pm

     
    1 package webshop::DeliverySection;
    2
    3 use Contenido::Section;
    4 @ISA = ('Contenido::Section');
    5
    6 sub extra_properties
    7 {
    8 return (
    9 { 'attr' => 'brief', 'type' => 'text', 'rusname' => 'Описание секции' },
    10 { 'attr' => 'default_document_class', 'default' => 'webshop::Delivery' },
    11 { 'attr' => '_sorted', 'default' => 1 },
    12 { 'attr' => 'filters', 'hidden' => 1 },
    13 { 'attr' => 'order_by', 'hidden' => 1 },
    14 )
    15 }
    16
    17 sub class_name
    18 {
    19 return 'Cпособы доставки';
    20 }
    21
    22 sub class_description
    23 {
    24 return 'Cпособы доставки';
    25 }
    26
    27 1;
  • utf8/plugins/webshop/lib/webshop/Init.pm

     
    1 package webshop::Init;
    2
    3 use strict;
    4 use warnings 'all';
    5
    6 use Contenido::Globals;
    7 use webshop::Apache;
    8 use webshop::Keeper;
    9
    10
    11 # загрузка всех необходимых плагину классов
    12 # webshop::SQL::SomeTable
    13 # webshop::SomeClass
    14 Contenido::Init::load_classes(qw(
    15 webshop::SQL::Basket
    16 webshop::SQL::Order
    17
    18 webshop::Address
    19 webshop::Basket
    20 webshop::Order
    21 webshop::Delivery
    22
    23 webshop::DeliverySection
    24 ));
    25
    26 sub init {
    27 push @{ $state->{'available_documents'} }, ('webshop::Basket', 'webshop::Order', 'webshop::Delivery');
    28 push @{ $state->{'available_sections'} }, 'webshop::DeliverySection';
    29 0;
    30 }
    31
    32 1;
  • utf8/plugins/webshop/lib/webshop/Keeper.pm

     
    1 package webshop::Keeper;
    2
    3 use strict;
    4 use warnings 'all';
    5 use base qw(Contenido::Keeper);
    6
    7 use Data::Dumper;
    8 use Contenido::Globals;
    9 use webshop::Basket;
    10 use webshop::SQL::Basket;
    11
    12 sub add_item {
    13 my $self = shift;
    14 my $object = shift;
    15 my (%options) = @_;
    16
    17 return unless ref $object;
    18 return unless $object->item_id && $object->number;
    19 return unless $object->uid || $object->session;
    20
    21
    22 my %opts;
    23 if ( $object->uid ) {
    24 $opts{uid} = $object->uid;
    25 } elsif ( $object->session ) {
    26 $opts{session} = $object->session;
    27 }
    28 my @items = $keeper->get_documents (
    29 class => 'webshop::Basket',
    30 status => [0,1],
    31 order_id=> 0,
    32 %opts,
    33 );
    34 my $total = 0;
    35 my $sum = 0;
    36 my $found = 0;
    37 if ( @items ) {
    38 foreach my $item ( @items ) {
    39 if ( $object->item_id == $item->item_id && $object->color_id == $item->color_id ) {
    40 $item->number($item->number + $object->number);
    41 $item->status(1);
    42 $item->store;
    43 $found = 1;
    44 }
    45 $total += $item->number;
    46 $sum += $item->number * $item->price;
    47 }
    48 }
    49 unless ( $found ) {
    50 $total += $object->number;
    51 $sum += $object->number * $object->price;
    52 $object->order_id(0);
    53 $object->store;
    54 }
    55 my @plugins = split (/[\ |\t]+/, $state->{plugins});
    56 if ( grep { $_ eq 'session' } @plugins ) {
    57 $keeper->{session}->store_value ( basket_total => $total, basket_sum => $sum );
    58 }
    59 return ($total, $sum);
    60 }
    61
    62 ### Метод приведения корзины для пользователя в момент логина
    63 #############################################################
    64 sub merge_basket {
    65 my $self = shift;
    66 my (%opts) = @_;
    67
    68 warn "Merge begin: ".Dumper(\%opts)."\n" if $DEBUG;
    69 return unless $opts{uid} && $opts{session};
    70
    71 my @items = $keeper->get_documents (
    72 class => 'webshop::Basket',
    73 status => [1,0],
    74 order_id=> 0,
    75 session => $opts{session},
    76 );
    77 foreach my $item ( @items ) {
    78 $item->session(undef);
    79 $item->uid( $opts{uid} );
    80 $item->store;
    81 }
    82 @items = $keeper->get_documents (
    83 class => 'webshop::Basket',
    84 status => 1,
    85 order_id=> 0,
    86 uid => $opts{uid},
    87 );
    88 my $total = 0;
    89 my $sum = 0;
    90 foreach my $item ( @items ) {
    91 $total += $item->number;
    92 $sum += $item->number * $item->price;
    93 }
    94 my @plugins = split (/[\ |\t]+/, $state->{plugins});
    95 if ( grep { $_ eq 'session' } @plugins ) {
    96 $keeper->{session}->store_value ( basket_total => $total, basket_sum => $sum );
    97 }
    98 warn "Merge end\n" if $DEBUG;
    99 return ($total, $sum);
    100 }
    101
    102
    103 sub get_basket {
    104 my $self = shift;
    105 my (%opts) = @_;
    106
    107 return unless $opts{uid} || $opts{session} || $opts{order_id};
    108
    109 my $uid = delete $opts{uid};
    110 my $session = delete $opts{session};
    111 unless ( exists $opts{order_id} && $opts{order_id} ) {
    112 $opts{order_id} = 0;
    113 if ( $uid ) {
    114 $opts{uid} = $uid;
    115 } elsif ( $session ) {
    116 $opts{session} = $session;
    117 }
    118 }
    119 $opts{status} = 1 unless exists $opts{status} && defined $opts{status};
    120 my @items = $keeper->get_documents (
    121 class => 'webshop::Basket',
    122 %opts,
    123 );
    124 my $total = 0;
    125 my $sum = 0;
    126 foreach my $item ( @items ) {
    127 if ( $item->status == 1 ) {
    128 $total += $item->number;
    129 $sum += $item->number * $item->price;
    130 }
    131 }
    132 my @plugins = split (/[\ |\t]+/, $state->{plugins});
    133 if ( grep { $_ eq 'session' } @plugins ) {
    134 $keeper->{session}->store_value ( basket_total => $total, basket_sum => $sum );
    135 }
    136 return \@items;
    137 }
    138
    139
    140 sub clear_basket {
    141 my $self = shift;
    142 my (%opts) = @_;
    143
    144 return unless exists $opts{uid} || exists $opts{session};
    145
    146 my $table_name = webshop::SQL::Basket->db_table;
    147 my $request = "delete from $table_name where order_id = 0 AND status = 1 AND";
    148 my $dbh = $keeper->SQL;
    149 my @vals;
    150 if ( exists $opts{uid} && $opts{uid} ) {
    151 $request .= " uid in (?)";
    152 push @vals, $opts{uid};
    153 } elsif ( exists $opts{session} ) {
    154 $request .= " session in (?)";
    155 push @vals, $opts{session};
    156 }
    157 warn "CLEAR: [$request]. VALS: [".join(',',@vals)."]\n" if $DEBUG;
    158 my $statement = $dbh->prepare ($request);
    159 $statement->execute( @vals ) || $log->error("DBI execute error on $request\n"."\ncalled with opts:\n".Data::Dumper::Dumper(\%opts));;
    160 $statement->finish;
    161
    162 my @plugins = split (/[\ |\t]+/, $state->{plugins});
    163 if ( grep { $_ eq 'session' } @plugins ) {
    164 $keeper->{session}->store_value ( basket_total => 0, basket_sum => 0 );
    165 }
    166 }
    167
    168
    169 sub clear_wishlist {
    170 my $self = shift;
    171 my (%opts) = @_;
    172
    173 return unless exists $opts{uid} || exists $opts{session};
    174
    175 my $table_name = webshop::SQL::Basket->db_table;
    176 my $request = "delete from $table_name where order_id = 0 AND status = 0 AND";
    177 my $dbh = $keeper->SQL;
    178 my @vals;
    179 if ( exists $opts{uid} ) {
    180 $request .= " uid in (?)";
    181 push @vals, $opts{uid};
    182 } elsif ( exists $opts{session} ) {
    183 $request .= " session in (?)";
    184 push @vals, $opts{session};
    185 }
    186 my $statement = $dbh->prepare ($request);
    187 $statement->execute( @vals ) || $log->error("DBI execute error on $request\n"."\ncalled with opts:\n".Data::Dumper::Dumper(\%opts));;
    188 $statement->finish;
    189 }
    190
    191
    192 ### Метод пересчета корзины
    193 # Принимает на вход параметры:
    194 # session => session_id пользователя
    195 # uid => UID пользователя
    196 # delete => массив или отдельный item_id
    197 # renumber => ссылка на хеш вида item => number
    198 #############################################################
    199 sub recount {
    200 my $self = shift;
    201 my (%opts) = @_;
    202
    203 warn "Recount Started!!!\n" if $DEBUG;
    204 return unless exists $opts{uid} || exists $opts{session} || exists $opts{order_id};
    205 my $basket = $self->get_basket ( %opts );
    206 return unless ref $basket eq 'ARRAY' && @$basket;
    207
    208 warn Dumper(\%opts) if $DEBUG;
    209
    210 my $total = 0;
    211 my $sum = 0;
    212 my @new_basket;
    213 my $session_no_store = delete $opts{session_no_store};
    214 foreach my $item ( @$basket ) {
    215 my $delete = 0;
    216 if ( exists $opts{renumber} && ref $opts{renumber} eq 'HASH' && exists $opts{renumber}{$item->id} && int($opts{renumber}{$item->id}) == 0 ) {
    217 $delete = 1;
    218 } elsif ( exists $opts{delete} && ref $opts{delete} eq 'ARRAY' ) {
    219 $delete = 1 if grep { $_ == $item->id } @{ $opts{delete} };
    220 } elsif ( exists $opts{delete} && $opts{delete} ) {
    221 $delete = 1 if $item->id == $opts{delete};
    222 }
    223 if ( $delete ) {
    224 warn "Item ID=".$item->id." DELETE\n" if $DEBUG;
    225 $item->delete();
    226 next;
    227 } else {
    228 my $store = 0;
    229 if ( exists $opts{renumber} && ref $opts{renumber} eq 'HASH' && exists $opts{renumber}{$item->id} && $opts{renumber}{$item->id} != $item->number ) {
    230 $item->number( $opts{renumber}{$item->id} );
    231 $store = 1;
    232 }
    233 if ( exists $opts{price} && ref $opts{price} eq 'HASH' && exists $opts{price}{$item->id} && $opts{price}{$item->id} != $item->price ) {
    234 $item->price( $opts{price}{$item->id} );
    235 $store = 1;
    236 }
    237 $item->store if $store;
    238 $total += $item->number;
    239 $sum += $item->number * $item->price;
    240 push @new_basket, $item;
    241 }
    242 }
    243 my @plugins = split (/[\ |\t]+/, $state->{plugins});
    244 if ( !$session_no_store && grep { $_ eq 'session' } @plugins ) {
    245 $keeper->{session}->store_value ( basket_total => $total, basket_sum => $sum );
    246 }
    247 return ($total, $sum, \@new_basket);
    248 }
    249
    250
    251 sub get_orders {
    252 my $self = shift;
    253 my (%opts) = @_;
    254
    255 my $list = delete $opts{list};
    256 $opts{order_by} ||= 'status';
    257 my @items = $keeper->get_documents (
    258 class => 'webshop::Order',
    259 %opts,
    260 );
    261 if ( exists $opts{id} && defined $opts{id} && !ref $opts{id} ) {
    262 if ( $list ) {
    263 $items[0]->{list} = $self->get_order_list( order_id => $opts{id} );
    264 }
    265 return $items[0];
    266 } else {
    267 if ( $list ) {
    268 map { $_->{list} = $self->get_order_list( order_id => $_->id ) } @items;
    269 }
    270 return \@items;
    271 }
    272 }
    273
    274
    275 sub get_order_list {
    276 my $self = shift;
    277 my (%opts) = @_;
    278
    279 return unless $opts{order_id};
    280
    281 $opts{status} = 1;
    282 my @items = $keeper->get_documents (
    283 class => 'webshop::Basket',
    284 %opts,
    285 );
    286 my $total = 0;
    287 my $sum = 0;
    288 foreach my $item ( @items ) {
    289 my $Item = $item->class->new( $keeper, $item->id );
    290 $item->{item} = $Item;
    291 if ( $item->status == 1 ) {
    292 $total += $item->number;
    293 $sum += $item->number * $item->price;
    294 }
    295 }
    296 return \@items;
    297 }
    298
    299 sub price_format {
    300 my $self = shift;
    301 my $price = shift;
    302
    303 $price = reverse $price;
    304 $price =~ s/(\d{3})/$1\ /g;
    305 $price = reverse $price;
    306
    307 return $price;
    308 }
    309
    310
    311 1;
  • utf8/plugins/webshop/lib/webshop/Order.pm

     
    1 package webshop::Order;
    2
    3 use base "Contenido::Document";
    4 sub extra_properties
    5 {
    6 return (
    7 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус заказа', facilshow => 1, postshow => 1,
    8 'cases' => [
    9 [0, 'открыт'],
    10 [1, 'обрабатывается'],
    11 [2, 'комплектуется'],
    12 [3, 'в доставке'],
    13 [4, 'доставлен'],
    14 [5, 'отклонен'],
    15 ],
    16 },
    17 { 'attr' => 'delivery', 'type' => 'lookup', 'rusname' => 'Тип доставки', facilshow => 1, postshow => 1,
    18 'lookup_opts' => {
    19 'class' => 'webshop::Delivery',
    20 },
    21 },
    22 { 'attr' => 'btime', 'type' => 'datetime', 'rusname' => 'Заказ отдан на комплектацию',
    23 postshow => 1, facilshow => 1 },
    24 { 'attr' => 'ftime', 'type' => 'datetime', 'rusname' => 'Заказ передан в доставку',
    25 manager_hidden => 1, postshow => 1, faciledit => 1 },
    26 { 'attr' => 'etime', 'type' => 'datetime', 'rusname' => 'Заказ доставлен',
    27 manager_hidden => 1, postedit => 1, facilshow => 1 },
    28 { 'attr' => 'num', 'type' => 'integer', 'rusname' => 'Количество позиций',
    29 manshow => 1, postshow => 1, facilshow => 1 },
    30 { 'attr' => 'sum', 'type' => 'string', 'rusname' => 'Сумма (total)', shortname => 'Сумма',
    31 column => 5, postshow => 1, facilshow => 1 },
    32 { 'attr' => 'sum_delivery', 'type' => 'string', 'rusname' => 'Стоимость доставки', shortname => 'Доставка',
    33 column => 6, postshow => 1, facilshow => 1 },
    34 { 'attr' => 'contact', 'type' => 'string', 'rusname' => 'Контактное лицо', facilshow => 1 },
    35 { 'attr' => 'email', 'type' => 'string', 'rusname' => 'E-mail для связи', shortname => 'E-mail',
    36 column => 3, postshow => 1, facilshow => 1 },
    37 { 'attr' => 'phone', 'type' => 'string', 'rusname' => 'Телефон для связи', shortname => 'Тел.',
    38 column => 4, postshow => 1, facilshow => 1 },
    39 { 'attr' => 'zipcode', 'type' => 'string', 'rusname' => 'Почтовый индекс', postshow => 1 },
    40 { 'attr' => 'town', 'type' => 'string', 'rusname' => 'Город', postshow => 1, facilshow => 1 },
    41 { 'attr' => 'metro', 'type' => 'string', 'rusname' => 'Ближайшее метро', postshow => 1 },
    42 { 'attr' => 'timeline', 'type' => 'string', 'rusname' => 'Предпочтительное время', postshow => 1 },
    43 { 'attr' => 'description', 'type' => 'text', 'rusname' => 'Описание для курьера', rows => 5, postshow => 1 },
    44 { 'attr' => 'facility_comment', 'type' => 'text', 'rusname' => 'Описание проблем с комплектацией', rows => 5, faciledit => 1 },
    45 { 'attr' => 'delivery_comment', 'type' => 'text', 'rusname' => 'Описание проблем с доставкой', rows => 5, postedit => 1 },
    46 { 'attr' => 'address', 'type' => 'text', 'rusname' => 'Адрес доставки', rows => 5, postedit => 1, facilshow => 1 },
    47 )
    48 }
    49
    50 sub sum_formatted {
    51 my $self = shift;
    52
    53 my $price = $self->sum;
    54 $price = reverse $price;
    55 $price =~ s/(\d{3})/$1\ /g;
    56 $price = reverse $price;
    57
    58 return $price;
    59 }
    60
    61 sub total_formatted {
    62 my $self = shift;
    63
    64 my $price = $self->sum + ($self->sum_delivery || 0);
    65 $price = reverse $price;
    66 $price =~ s/(\d{3})/$1\ /g;
    67 $price = reverse $price;
    68
    69 return $price;
    70 }
    71
    72
    73 sub reject {
    74 my $self = shift;
    75
    76 my $query = $self->{keeper}->SQL->prepare("delete from basket where order_id = ? and uid = ?");
    77 $query->execute( $self->id, $self->uid );
    78 $self->delete;
    79 }
    80
    81
    82 sub class_name
    83 {
    84 return 'Заказ';
    85 }
    86
    87 sub class_description
    88 {
    89 return 'Заказ';
    90 }
    91
    92 sub class_table
    93 {
    94 return 'webshop::SQL::Order';
    95 }
    96
    97
    98 sub post_delete
    99 {
    100 my $self = shift;
    101 my @items = $self->keeper->get_documents(
    102 class => 'webshop::Basket',
    103 order_id => $self->id,
    104 );
    105 foreach my $item ( @items ) {
    106 $item->delete( attachments => 1 );
    107 }
    108 1;
    109 }
    110
    111 1;
  • utf8/plugins/webshop/lib/webshop/SQL/AddressTable.pm

     
    1 package webshop::SQL::AddressTable;
    2
    3 use base 'SQL::DocumentTable';
    4
    5 sub db_table
    6 {
    7 return 'adresses';
    8 }
    9
    10 my $available_filters = [qw(
    11
    12 _class_filter
    13 _status_filter
    14 _in_id_filter
    15 _id_filter
    16 _name_filter
    17 _class_excludes_filter
    18 _sfilter_filter
    19 _excludes_filter
    20 _datetime_filter
    21 _date_equal_filter
    22 _date_filter
    23 _previous_days_filter
    24 _s_filter
    25
    26 _uid_filter
    27 )];
    28
    29 sub available_filters {
    30 return $available_filters;
    31 }
    32
    33
    34 # ----------------------------------------------------------------------------
    35 # Свойства храним в массивах, потому что порядок важен!
    36 # Это общие свойства - одинаковые для всех документов.
    37 #
    38 # attr - обязательный параметр, название атрибута;
    39 # type - тип аттрибута, требуется для отображдения;
    40 # rusname - русское название, опять же требуется для отображения;
    41 # hidden - равен 1, когда
    42 # readonly - инициализации при записи только без изменения в дальнейшем
    43 # db_field - поле в таблице
    44 # default - значение по умолчанию (поле всегда имеет это значение)
    45 # ----------------------------------------------------------------------------
    46 sub required_properties
    47 {
    48 my $self = shift;
    49
    50 my @parent_properties = $self->SUPER::required_properties;
    51 return (
    52 @parent_properties,
    53 { # User ID
    54 'attr' => 'uid',
    55 'type' => 'string',
    56 'rusname' => 'ID пользователя',
    57 # 'hidden' => 1,
    58 'db_field' => 'uid',
    59 'db_type' => 'integer',
    60 'db_opts' => "not null default 0",
    61 'default' => 0,
    62 },
    63 );
    64 }
    65
    66 ########### FILTERS DESCRIPTION ###############################################################################
    67 sub _uid_filter {
    68 my ($self,%opts)=@_;
    69 return undef unless ( exists $opts{uid} );
    70 return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
    71 }
    72
    73 1;
  • utf8/plugins/webshop/lib/webshop/SQL/Basket.pm

     
    1 package webshop::SQL::Basket;
    2
    3 use base 'SQL::DocumentTable';
    4
    5 sub db_table
    6 {
    7 return 'basket';
    8 }
    9
    10
    11 sub available_filters {
    12 my @available_filters = qw(
    13
    14 _class_filter
    15 _status_filter
    16 _in_id_filter
    17 _id_filter
    18 _name_filter
    19 _class_excludes_filter
    20 _sfilter_filter
    21 _excludes_filter
    22 _datetime_filter
    23 _date_equal_filter
    24 _date_filter
    25 _previous_days_filter
    26 _s_filter
    27
    28 _color_filter
    29 _session_filter
    30 _uid_filter
    31 _order_id_filter
    32 _item_filter
    33 );
    34
    35 return \@available_filters;
    36 }
    37
    38 # ----------------------------------------------------------------------------
    39 # Свойства храним в массивах, потому что порядок важен!
    40 # Это общие свойства - одинаковые для всех документов.
    41 #
    42 # attr - обязательный параметр, название атрибута;
    43 # type - тип аттрибута, требуется для отображдения;
    44 # rusname - русское название, опять же требуется для отображения;
    45 # hidden - равен 1, когда
    46 # readonly - инициализации при записи только без изменения в дальнейшем
    47 # db_field - поле в таблице
    48 # default - значение по умолчанию (поле всегда имеет это значение)
    49 # ----------------------------------------------------------------------------
    50 sub required_properties
    51 {
    52 my $self = shift;
    53
    54 my @parent_properties = $self->SUPER::required_properties;
    55 return (
    56 @parent_properties,
    57 {
    58 'attr' => 'uid',
    59 'type' => 'integer',
    60 'rusname' => 'Идентификатор пользователя',
    61 'lookup_opts' => {
    62 'class' => $self->profile_class(),
    63 'search_by' => 'login',
    64 },
    65 'db_field' => 'uid',
    66 'db_type' => 'integer',
    67 'db_opts' => "default 0",
    68 },
    69 { # ID товара
    70 'attr' => 'item_id',
    71 'type' => 'integer',
    72 'rusname' => 'ID товара',
    73 'hidden' => 1,
    74 'db_field' => 'item_id',
    75 'db_type' => 'integer',
    76 'db_opts' => "not null",
    77 },
    78 {
    79 'attr' => 'item_class',
    80 'type' => 'string',
    81 'rusname' => 'Класс товарной позиции',
    82 'hidden' => 1,
    83 'db_field' => 'item_class',
    84 'db_type' => 'text',
    85 },
    86 {
    87 'attr' => 'item_table',
    88 'type' => 'string',
    89 'rusname' => 'Класс таблицы товарной позиции',
    90 'hidden' => 1,
    91 'db_field' => 'item_table',
    92 'db_type' => 'text',
    93 },
    94 {
    95 'attr' => 'number',
    96 'type' => 'integer',
    97 'rusname' => 'Количество позиций',
    98 'db_field' => 'number',
    99 'db_type' => 'integer',
    100 'db_opts' => "default 0",
    101 },
    102 {
    103 'attr' => 'price',
    104 'type' => 'string',
    105 'rusname' => 'Цена позиции',
    106 'db_field' => 'price',
    107 'db_type' => 'float',
    108 'db_opts' => "default 0",
    109 },
    110 { # ID заказа
    111 'attr' => 'order_id',
    112 'type' => 'integer',
    113 'rusname' => 'ID заказа',
    114 'hidden' => 1,
    115 'db_field' => 'order_id',
    116 'db_type' => 'integer',
    117 'db_opts' => "default 0",
    118 },
    119 { # ID цвета
    120 'attr' => 'color_id',
    121 'type' => 'integer',
    122 'rusname' => 'ID цвета',
    123 'hidden' => 1,
    124 'db_field' => 'color_id',
    125 'db_type' => 'integer',
    126 },
    127 { # ID Сессии
    128 'attr' => 'session',
    129 'type' => 'string',
    130 'rusname' => 'ID Сессии пользователя',
    131 'db_field' => 'session',
    132 'db_type' => 'text',
    133 },
    134 );
    135 }
    136
    137
    138 sub profile_class () {
    139 my $self = shift;
    140 return ref $self->{keeper} ? $self->{keeper}{webshop}{state}->profile_document_class : undef;
    141 }
    142
    143
    144 ########### FILTERS DESCRIPTION ###############################################################################
    145 sub _uid_filter {
    146 my ($self,%opts)=@_;
    147 return undef unless ( exists $opts{uid} );
    148 return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
    149 }
    150
    151 sub _session_filter {
    152 my ($self,%opts)=@_;
    153 return undef unless ( exists $opts{session} );
    154 return &SQL::Common::_generic_text_filter('d.session', $opts{session});
    155 }
    156
    157 sub _item_filter {
    158 my ($self,%opts)=@_;
    159 return undef unless ( exists $opts{item} );
    160 return &SQL::Common::_generic_int_filter('d.item_id', $opts{item});
    161 }
    162
    163 sub _color_filter {
    164 my ($self,%opts)=@_;
    165 return undef unless ( exists $opts{color} );
    166 return &SQL::Common::_generic_int_filter('d.color_id', $opts{color});
    167 }
    168
    169 sub _order_id_filter {
    170 my ($self,%opts)=@_;
    171 return undef unless ( exists $opts{order_id} );
    172 return &SQL::Common::_generic_int_filter('d.order_id', $opts{order_id});
    173 }
    174
    175
    176 1;
  • utf8/plugins/webshop/lib/webshop/SQL/Order.pm

     
    1 package webshop::SQL::Order;
    2
    3 use base 'SQL::DocumentTable';
    4
    5 sub db_table
    6 {
    7 return 'orders';
    8 }
    9
    10 my $available_filters = [qw(
    11
    12 _class_filter
    13 _status_filter
    14 _in_id_filter
    15 _id_filter
    16 _name_filter
    17 _class_excludes_filter
    18 _sfilter_filter
    19 _excludes_filter
    20 _datetime_filter
    21 _date_equal_filter
    22 _date_filter
    23 _previous_days_filter
    24 _s_filter
    25
    26 _uid_filter
    27 )];
    28
    29 sub available_filters {
    30 return $available_filters;
    31 }
    32
    33 my @required_properties = (
    34 { # Идентификатор документа, сквозной по всем типам...
    35 'attr' => 'id',
    36 'type' => 'integer',
    37 'rusname' => 'Идентификатор документа',
    38 'hidden' => 1,
    39 'readonly' => 1,
    40 'auto' => 1,
    41 'db_field' => 'id',
    42 'db_type' => 'integer',
    43 'db_opts' => "not null default nextval('public.documents_id_seq'::text)",
    44 },
    45 { # Класс документа...
    46 'attr' => 'class',
    47 'type' => 'string',
    48 'rusname' => 'Класс документа',
    49 'hidden' => 1,
    50 'readonly' => 1,
    51 'db_field' => 'class',
    52 'db_type' => 'varchar(48)',
    53 'db_opts' => 'not null',
    54 },
    55 { # Название (не используется)
    56 'attr' => 'name',
    57 'type' => 'string',
    58 'rusname' => 'Имя заказчика',
    59 'column' => 2,
    60 'db_field' => 'name',
    61 'db_type' => 'varchar(255)',
    62 },
    63 { # User ID
    64 'attr' => 'uid',
    65 'type' => 'string',
    66 'rusname' => 'ID пользователя',
    67 # 'hidden' => 1,
    68 'db_field' => 'uid',
    69 'db_type' => 'integer',
    70 'db_opts' => "not null default 0",
    71 'default' => 0,
    72 },
    73 { # User ID
    74 'attr' => 'manager_id',
    75 'type' => 'string',
    76 'rusname' => 'ID менеджера',
    77 'hidden' => 1,
    78 'db_field' => 'manager_id',
    79 'db_type' => 'integer',
    80 'db_opts' => "not null default 0",
    81 'default' => 0,
    82 },
    83 { # User ID
    84 'attr' => 'vault_id',
    85 'type' => 'string',
    86 'rusname' => 'ID специалиста комплектации',
    87 'hidden' => 1,
    88 'db_field' => 'vault_id',
    89 'db_type' => 'integer',
    90 'db_opts' => "not null default 0",
    91 'default' => 0,
    92 },
    93 { # User ID
    94 'attr' => 'postman_id',
    95 'type' => 'string',
    96 'rusname' => 'ID курьера',
    97 'hidden' => 1,
    98 'db_field' => 'postman_id',
    99 'db_type' => 'integer',
    100 'db_opts' => "not null default 0",
    101 'default' => 0,
    102 },
    103 { # Время создания документа, служебное поле...
    104 'attr' => 'ctime',
    105 'type' => 'datetime',
    106 'rusname' => 'Время создания',
    107 'readonly' => 1,
    108 'auto' => 1,
    109 'hidden' => 1,
    110 'db_field' => 'ctime',
    111 'db_type' => 'timestamp',
    112 'db_opts' => 'not null default now()',
    113 'default' => 'CURRENT_TIMESTAMP',
    114 },
    115 { # Время модификации документа, служебное поле...
    116 'attr' => 'mtime',
    117 'type' => 'datetime',
    118 'rusname' => 'Время модификации',
    119 'hidden' => 1,
    120 'auto' => 1,
    121 'db_field' => 'mtime',
    122 'db_type' => 'timestamp',
    123 'db_opts' => 'not null default now()',
    124 'default' => 'CURRENT_TIMESTAMP',
    125 },
    126 { # Дата и время документа...
    127 'attr' => 'dtime',
    128 'type' => 'datetime',
    129 'rusname' => 'Заказ подтвержден',
    130 'column' => 1,
    131 'postshow' => 1,
    132 'facilshow' => 1,
    133 'db_field' => 'dtime',
    134 'db_type' => 'timestamp',
    135 'db_opts' => 'not null default now()',
    136 'default' => 'CURRENT_TIMESTAMP',
    137 },
    138 { # Массив секций, обрабатывается специальным образом...
    139 'attr' => 'sections',
    140 'type' => 'sections_list',
    141 'rusname' => 'Секции',
    142 'hidden' => 1,
    143 'db_field' => 'sections',
    144 'db_type' => 'integer[]',
    145 },
    146 { # Одно поле статуса является встроенным...
    147 'attr' => 'status',
    148 'type' => 'status',
    149 'postshow' => 1,
    150 'facilshow' => 1,
    151 'column' => 7,
    152 'rusname' => 'Статус',
    153 'db_field' => 'status',
    154 'db_type' => 'integer',
    155 },
    156 );
    157
    158 # ----------------------------------------------------------------------------
    159 # Свойства храним в массивах, потому что порядок важен!
    160 # Это общие свойства - одинаковые для всех документов.
    161 #
    162 # attr - обязательный параметр, название атрибута;
    163 # type - тип аттрибута, требуется для отображдения;
    164 # rusname - русское название, опять же требуется для отображения;
    165 # hidden - равен 1, когда
    166 # readonly - инициализации при записи только без изменения в дальнейшем
    167 # db_field - поле в таблице
    168 # default - значение по умолчанию (поле всегда имеет это значение)
    169 # ----------------------------------------------------------------------------
    170 sub required_properties
    171 {
    172 return @required_properties;
    173 }
    174
    175 ########### FILTERS DESCRIPTION ###############################################################################
    176 sub _uid_filter {
    177 my ($self,%opts)=@_;
    178 return undef unless ( exists $opts{uid} );
    179 return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
    180 }
    181
    182 1;
  • utf8/plugins/webshop/lib/webshop/State.pm.proto

     
    1 package webshop::State;
    2
    3 use strict;
    4 use warnings 'all';
    5 use vars qw($AUTOLOAD);
    6
    7
    8 sub new {
    9 my ($proto) = @_;
    10 my $class = ref($proto) || $proto;
    11 my $self = {};
    12 bless $self, $class;
    13
    14 # зашитая конфигурация плагина
    15 $self->{db_type} = 'none';
    16 $self->{db_keepalive} = 0;
    17 # $self->{db_host} = '';
    18 # $self->{db_name} = '';
    19 # $self->{db_user} = '';
    20 # $self->{db_password} = '';
    21 # $self->{db_port} = '';
    22 $self->{profile_document_class} = '@PROFILE_DOCUMENT_CLASS@' || 'users::UserProfile';
    23 $self->{item_document_class} = '@ITEM_DOCUMENT_CLASS@' || 'webshop::Item';
    24
    25 $self->_init_();
    26 $self;
    27 }
    28
    29 sub info {
    30 my $self = shift;
    31 return unless ref $self;
    32
    33 for (sort keys %{$self->{attributes}}) {
    34 my $la = length $_;
    35 warn "\t$_".("\t" x (2-int($la/8))).": $self->{$_}\n";
    36 }
    37 }
    38
    39 sub _init_ {
    40 my $self = shift;
    41
    42 # зашитая конфигурация плагина
    43 $self->{attributes}->{$_} = 'SCALAR' for qw(
    44 profile_document_class
    45 item_document_class
    46 db_type
    47 db_keepalive
    48 );
    49 # db_keepalive
    50 # db_host
    51 # db_port
    52 # db_name
    53 # db_user
    54 # db_password
    55 }
    56
    57 sub AUTOLOAD {
    58 my $self = shift;
    59 my $attribute = $AUTOLOAD;
    60
    61 $attribute =~ s/.*:://;
    62 return unless $attribute =~ /[^A-Z]/; # Отключаем методы типа DESTROY
    63
    64 if (!exists $self->{attributes}->{$attribute}) {
    65 warn "Contenido Error (webshop::State): Вызов метода, для которого не существует обрабатываемого свойства: ->$attribute()\n";
    66 return;
    67 }
    68
    69 $self->{$attribute} = shift @_ if $#_>=0;
    70 $self->{$attribute};
    71 }
    72
    73 1;
  • utf8/plugins/webshop/sql/TOAST/adresses.sql

     
    1 CREATE TABLE adresses (
    2 id integer DEFAULT nextval(('public.documents_id_seq'::text)::regclass) NOT NULL,
    3 ctime timestamp without time zone DEFAULT now() NOT NULL,
    4 mtime timestamp without time zone DEFAULT now() NOT NULL,
    5 dtime timestamp without time zone DEFAULT now() NOT NULL,
    6 class text DEFAULT 'webshop::Address'::text NOT NULL,
    7 status smallint default 0 NOT NULL,
    8 sections integer,
    9 uid integer not null,
    10 name text,
    11 data text
    12 );
    13
    14 CREATE INDEX adresses_sections ON adresses USING btree (sections);
    15 CREATE INDEX adresses_uid ON adresses USING btree (uid);
  • utf8/plugins/webshop/sql/TOAST/basket.sql

     
    1 CREATE TABLE basket (
    2 id integer DEFAULT nextval(('public.documents_id_seq'::text)::regclass) NOT NULL,
    3 ctime timestamp without time zone DEFAULT now() NOT NULL,
    4 mtime timestamp without time zone DEFAULT now() NOT NULL,
    5 dtime timestamp without time zone DEFAULT now() NOT NULL,
    6 class text DEFAULT 'webshop::Basket'::text NOT NULL,
    7 status smallint default 0 NOT NULL,
    8 sections integer[],
    9 uid integer,
    10 item_id integer not null,
    11 item_class text,
    12 item_table text,
    13 order_id integer,
    14 color_id integer,
    15 session text,
    16 number integer default 0,
    17 price float default 0,
    18 name text,
    19 data text
    20 );
    21
    22 CREATE INDEX basket_order_id ON basket USING btree (order_id);
    23 CREATE INDEX basket_sections ON basket USING gist (sections);
    24 CREATE INDEX basket_session ON basket USING btree (session) where session is not null;
    25 CREATE INDEX basket_uid ON basket USING btree (uid);
  • utf8/plugins/webshop/sql/TOAST/orders.sql

     
    1 CREATE TABLE orders (
    2 id integer DEFAULT nextval(('public.documents_id_seq'::text)::regclass) NOT NULL,
    3 ctime timestamp without time zone DEFAULT now() NOT NULL,
    4 mtime timestamp without time zone DEFAULT now() NOT NULL,
    5 dtime timestamp without time zone DEFAULT now() NOT NULL,
    6 class text DEFAULT 'webshop::Order'::text NOT NULL,
    7 status smallint default 0 NOT NULL,
    8 sections integer[],
    9 uid integer,
    10 manager_id integer,
    11 vault_id integer,
    12 postman_id integer,
    13 session text,
    14 name text,
    15 data text
    16 );
    17
    18 CREATE INDEX orders_sections ON orders USING gist (sections);
    19 CREATE INDEX orders_session ON orders USING btree (session) where session is not null;
    20 CREATE INDEX orders_uid ON orders USING btree (uid) where uid is not null;

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

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

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

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

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