1
doc.zayavka.php in web/include – MultiMag

source: web/include/doc.zayavka.php @ 1c9737e

Last change on this file since 1c9737e was 1c9737e, checked in by BlackLight <blacklight@…>, 2 years ago
  • Добавлена поддержка импорта платёжных поручений из формата банк-клиента 1.03
  • Экспорт CSV вынесен во внешние печатные формы
  • Заявка на комплектующие вынесена во внешние печатные формы
  • Рефакторинг: вынес получение списка модулей в ядро
  • Property mode set to 100644
File size: 32.9 KB
Line 
1<?php
2//      MultiMag v0.2 - Complex sales system
3//
4//      Copyright (C) 2005-2018, BlackLight, TND Team, http://tndproject.org
5//
6//      This program is free software: you can redistribute it and/or modify
7//      it under the terms of the GNU Affero General Public License as
8//      published by the Free Software Foundation, either version 3 of the
9//      License, or (at your option) any later version.
10//
11//      This program is distributed in the hope that it will be useful,
12//      but WITHOUT ANY WARRANTY; without even the implied warranty of
13//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14//      GNU Affero General Public License for more details.
15//
16//      You should have received a copy of the GNU Affero General Public License
17//      along with this program.  If not, see <http://www.gnu.org/licenses/>.
18//
19
20/// Документ *Заявка покупателя*
21class doc_Zayavka extends doc_Nulltype {
22    /// Конструктор
23    /// @param doc id документа
24    function __construct($doc = 0) {
25        $this->def_dop_data = [
26            'status' => '',
27            'pie' => 0,
28            'buyer_phone' => '',
29            'buyer_email' => '',
30            'delivery' => 0,
31            'delivery_address' => '',
32            'delivery_date' => '',
33            'delivery_region' => '',
34            'ishop' => 0,
35            'buyer_rname' => '',
36            'buyer_ip' => '',
37            'pay_type' => '',
38            'cena' => '',
39            'worker_id' => 0
40        ];
41        parent::__construct($doc);
42        $this->doc_type = 3;
43        $this->typename = 'zayavka';
44        $this->viewname = 'Заявка покупателя';
45        $this->sklad_editor_enable = true;
46        $this->header_fields = 'bank sklad separator agent cena';
47        settype($this->id, 'int');       
48    }
49   
50    public function getExtControls() {
51        return $this->ext_controls = array(
52            'ishop' => [
53                'type' => 'label_flag',
54                'label' => 'Заявка интернет-магазина',
55            ],
56            'buyer_info' => [
57                'type' => 'buyer_info',
58            ],
59            'delivery_info' => [
60                'type' => 'delivery_info',
61            ],         
62            'pay_type' => [
63                'type' => 'select',               
64                'label' => 'Способ оплаты',
65                'data_source' => 'paytype.listnames',
66            ],
67            'worker_id' => [
68                'type' => 'select',               
69                'label' => 'Сотрудник',
70                'data_source' => 'worker.listnames',
71            ],
72        );
73    }
74
75    /// Получить строку с HTML кодом дополнительных кнопок документа
76    protected function getAdditionalButtonsHTML() {
77        global $CONFIG;
78        $ret = "<a href='#' onclick=\"msgMenu(event, '{$this->id}')\" title='Отправить сообщение покупателю'><img src='/img/i_mailsend.png' alt='msg'></a>";       
79        if (@$CONFIG['doc']['pie'] && !@$this->dop_data['pie']) {
80            $ret.="<a href='#' onclick=\"sendPie(event, '{$this->id}')\" title='Отправить благодарность покупателю'><img src='/img/i_pie.png' alt='pie'></a>";
81        }
82        $r_lock = '';
83        if($this->getDopData('reserved')) {
84            $r_action = "Снять";
85        }
86        else {
87            $r_action = "Разрешить";
88            $r_lock = 'un';
89        }
90        $ret.="<a href='#' onclick=\"toggleReserve(event, '{$this->id}')\" title='{$r_action} резервы'><img src='/img/22x22/object-{$r_lock}locked.png' alt='{$r_action} резервы'></a>";
91        return $ret;
92    }
93       
94    /// Функция обработки событий, связанных  с заказом
95    /// @param event_name Полное название события
96    public function dispatchZEvent($event_name, $initator = null) {
97        global $CONFIG;
98        if(@$CONFIG['zstatus']['debug']) {
99            doc_log("EVENT", "$event_name, cur_status:{$this->dop_data['status']}", 'doc', $this->id);
100        }
101        if($initator instanceof doc_Realizaciya) {
102            switch ($event_name) {
103                case 'pre-apply':
104                case 'pre-cancel':
105                    $this->unsetReserves();                   
106                    break;
107                case 'cancel':
108                case 'apply':
109                    $this->setReserves();
110                    break;
111            }
112        }
113        if (isset($CONFIG['zstatus'][$event_name])) {
114            $s = array('{DOC}', '{SUM}', '{DATE}');
115            $r = array($this->id, $this->doc_data['sum'], date('Y-m-d', $this->doc_data['date']));
116            foreach($this->doc_data as $name => $value) {
117                $s[] = '{'.strtoupper($name).'}';
118                $r[] = $value;
119            }
120            foreach($this->dop_data as $name => $value) {
121                $s[] = '{DOP_'.strtoupper($name).'}';
122                $r[] = $value;
123            }
124            if($initator) {
125                foreach($initator->doc_data as $name => $value) {
126                    $s[] = '{I_'.strtoupper($name).'}';
127                    $r[] = $value;
128                }
129                foreach($initator->dop_data as $name => $value) {
130                    $s[] = '{I_DOP_'.strtoupper($name).'}';
131                    $r[] = $value;
132                }
133            }
134            // Проверка и повышение статуса. Если повышение не произошло - остальные действия не выполняются
135            if (isset($CONFIG['zstatus'][$event_name]['testup_status'])) {
136                $status = $CONFIG['zstatus'][$event_name]['testup_status'];
137                $status_options = array(0 => 'new', 1 => 'inproc', 2 => 'ready', 3 => 'ok', 4 => 'err');
138                // Если устанавливаемый статус не стандартный - прервать тест
139                if (!in_array($status, $status_options)) {
140                    return false;
141                }
142                // Если текущий статус не стандартный - прервать тест
143                if (@$this->dop_data['status'] == $status) {
144                    return false;
145                }
146                // Если устанавливаемый статус равен текущему - прервать тест
147                if ($this->dop_data['status'] == $status) {
148                    return false;
149                }
150                // Если статус меняется на уменьшение - прервать тест
151                if (array_search($this->dop_data['status'], $status_options) >= array_search($status, $status_options)) {
152                    return false;
153                }
154                $this->setDopData('status', $status);
155            }
156
157            foreach ($CONFIG['zstatus'][$event_name] as $trigger => $value) {
158                switch ($trigger) {
159                    case 'set_status': // Установить статус
160                        $this->setDopData('status', $value);
161                        break;
162                    case 'send_sms': // Послать sms сообщение
163                        $value = str_replace($s, $r, $value);
164                        $this->sendSMSNotify($value);
165                        break;
166                    case 'send_email': // Послать email сообщение
167                        $value = str_replace($s, $r, $value);
168                        $this->sendEmailNotify($value);
169                        break;
170                    case 'send_xmpp': // Послать XMPP сообщение
171                        $value = str_replace($s, $r, $value);
172                        $this->sendXMPPNotify($value);
173                        break;
174                    case 'notify':  // Известить всеми доступными способами
175                        $value = str_replace($s, $r, $value);
176                        $this->sendNotify($value); 
177                        break;
178
179                    /// TODO:
180                    /// Отправка по телефону (голосом)
181                    /// Отправка по телефону (факсом)
182                }
183            }
184            return true;
185        }
186        return false;
187    }
188
189    /// Отправить SMS с заданным текстом заказчику на первый из подходящих номеров
190    /// @param text текст отправляемого сообщения
191    function sendSMSNotify($text) {
192        global $db;
193        if (!\cfg::get('doc', 'notify_sms')) {
194            return false;
195        } 
196        $smsphone = '';
197        if (isset($this->dop_data['buyer_phone'])) {
198            if(preg_match('/^\+79\d{9}$/', $this->dop_data['buyer_phone'])) {
199                $smsphone = $this->dop_data['buyer_phone'];
200            }
201        } 
202        if ($this->doc_data['agent'] > 1 && !$smsphone) {
203            $agent = new \models\agent($this->doc_data['agent']);
204            $smsphone = $agent->getSMSPhone();               
205        }
206        if (!$smsphone && $this->dop_data['ishop']) {
207            $user_data = $db->selectRowA('users', $this->doc_data['user'], array('reg_phone'));
208            if (isset($user_data['reg_phone'])) {
209                $smsphone = $user_data['reg_phone'];
210            }
211        }
212        if (preg_match('/^\+79\d{9}$/', $smsphone)) {
213            require_once('include/sendsms.php');
214            $sender = new SMSSender();
215            $sender->setNumber($smsphone);
216            $sender->setContent($text);
217            $sender->send();
218            if( \cfg::get('doc', 'notify_debug') ) {
219                doc_log("NOTIFY SMS", "number:$smsphone; text:$text", 'doc', $this->id);
220            } 
221            return true;
222        }
223        return false;
224    }
225
226    /// Отправить email с заданным текстом заказчику на все доступные адреса
227    /// @param text текст отправляемого сообщения
228    function sendEmailNotify($text, $subject=null) {
229        global $db;
230        $pref = \pref::getInstance();
231        if (!\cfg::get('doc', 'notify_email') ) {
232            return false;
233        }
234        $emails = array();
235        if (isset($this->dop_data['buyer_email'])) {
236            if($this->dop_data['buyer_email']) {
237                $emails[$this->dop_data['buyer_email']] = $this->dop_data['buyer_email'];
238            }
239        }
240        if ($this->doc_data['agent'] > 1) { // Частному лицу не рассылаем
241            $agent = new \models\agent($this->doc_data['agent']);
242            $contacts = $agent->contacts;
243            foreach($contacts as $line) {
244                if($line['type']=='email' && $line['value']) {
245                    $emails[$line['value']] = $line['value'];
246                }
247            }
248        }
249        if($this->dop_data['ishop']) {
250            $user_data = $db->selectRowA('users', $this->doc_data['user'], array('reg_email'));
251            if (isset($user_data['reg_email'])) {
252                if($user_data['reg_email']) {
253                    $emails[$user_data['reg_email']] = $user_data['reg_email'];
254                }
255            }
256        }
257        if(count($emails)>0) {
258            foreach($emails as $email) {
259                $user_msg = "Уважаемый клиент!\n" . $text;
260                if(!$subject) {
261                    $subject = "Заказ N {$this->id} на {$pref->site_name}";
262                }
263                mailto($email, $subject, $user_msg);
264                if( \cfg::get('doc', 'notify_debug') ) {
265                    doc_log("NOTIFY Email", "email:$email; text:$user_msg", 'doc', $this->id);
266                }
267            }
268            return true;
269        }
270        return false;
271    }
272   
273    /// Отправить сообщение по XMPP с заданным текстом заказчику на все доступные адреса
274    /// @param text текст отправляемого сообщения
275    function sendXMPPNotify($text) {
276        global $db;
277        if (!\cfg::get('doc', 'notify_xmpp')) {
278            return false;
279        }
280        $addresses = array();
281        if ($this->doc_data['agent'] > 1) {
282            $agent = new \models\agent($this->doc_data['agent']);
283            $contacts = $agent->contacts;
284            foreach($contacts as $line) {
285                if($line['type']=='jid' || $line['type']=='xmpp') {
286                    $addresses[$line['value']] = $line['value'];
287                }
288            }
289        }
290        if($this->dop_data['ishop']) {
291            $user_data = $db->selectRowA('users', $this->doc_data['user'], array('jid'));
292            if (isset($user_data['jid'])) {
293                $addresses[] = $user_data['jid'];
294            }
295        }
296        if(count($addresses)>0) {
297            require_once(\cfg::getroot('location').'/common/XMPPHP/XMPP.php');
298            $xmppclient = new \XMPPHP\XMPP( 
299                \cfg::get('xmpp', 'host'), \cfg::get('xmpp', 'port'), \cfg::get('xmpp', 'login'), \cfg::get('xmpp', 'pass'), 'MultiMag r'.MULTIMAG_REV);
300            $xmppclient->connect();
301            $xmppclient->processUntil('session_start');
302            $xmppclient->presence();
303            foreach($addresses as $addr) {               
304                $xmppclient->message($addr, $text);                   
305                if(\cfg::get('doc','notify_debug') ) {
306                    doc_log("NOTIFY xmpp", "jid:$addr; text:$text", 'doc', $this->id);
307                }
308            }
309            $xmppclient->disconnect();
310            return true;
311        }
312        return false;
313    }
314
315    function DopHead() {
316        global $tmpl, $CONFIG, $db;
317        if (!isset($this->dop_data['delivery_date'])) {
318            $this->dop_data['delivery_date'] = '';
319        }
320
321        $tmpl->addContent("<hr>");
322
323        if (@$this->dop_data['ishop']) {
324            $tmpl->addContent("<b>Заявка с интернет-витрины</b><br>");
325        }
326        if (@$this->dop_data['buyer_rname']) {
327            $tmpl->addContent("<b>ФИО: </b>{$this->dop_data['buyer_rname']}<br>");
328        }
329        if (@$this->dop_data['buyer_ip']) {
330            $tmpl->addContent("<b>IP адрес: </b>{$this->dop_data['buyer_ip']}<br>");
331        }
332        if (@$this->dop_data['pay_type']) {
333            $tmpl->addContent("<b>Способ оплаты: </b>");
334            $ldo = new \Models\LDO\paytypes();
335            $paytypes = $ldo->getData();
336            if(isset($paytypes[$this->dop_data['pay_type']])) {
337                $tmpl->addContent($paytypes[$this->dop_data['pay_type']]);
338            }
339            else {
340                $tmpl->addContent("не определён ({$this->dop_data['pay_type']})");
341            }
342            $tmpl->addContent("<br>");
343        }
344        if (!isset($this->dop_data['buyer_email'])) {
345            $this->dop_data['buyer_email'] = '';
346        }
347        if (!isset($this->dop_data['buyer_phone'])) {
348            $this->dop_data['buyer_phone'] = '';
349        }
350        $tmpl->addContent("e-mail, прикреплённый к заявке<br><input type='text' name='buyer_email' style='width: 100%' value='{$this->dop_data['buyer_email']}'><br>");
351        $tmpl->addContent("Телефон для sms, прикреплённый к заявке<input type='text' name='buyer_phone' style='width: 100%' value='{$this->dop_data['buyer_phone']}'><br>");
352
353        $tmpl->addContent("Доставка:<br><select name='delivery'><option value='0'>Не требуется</option>");
354        $res = $db->query("SELECT `id`, `name` FROM `delivery_types` ORDER BY `id`");
355        while ($nxt = $res->fetch_row()) {
356            if ($nxt[0] == $this->dop_data['delivery']) {
357                $tmpl->addContent("<option value='$nxt[0]' selected>" . html_out($nxt[1]) . "</option>");
358            } else {
359                $tmpl->addContent("<option value='$nxt[0]'>" . html_out($nxt[1]) . "</option>");
360            }
361        }
362
363        $tmpl->addContent("</select>
364            Регион доставки:<br><select name='delivery_region'><option value='0'>Не задан</option>");
365        $res = $db->query("SELECT `id`, `name` FROM `delivery_regions` ORDER BY `id`");
366        while ($nxt = $res->fetch_row()) {
367            if ($nxt[0] == $this->dop_data['delivery_region']) {
368                $tmpl->addContent("<option value='$nxt[0]' selected>" . html_out($nxt[1]) . "</option>");
369            } else {
370                $tmpl->addContent("<option value='$nxt[0]'>" . html_out($nxt[1]) . "</option>");
371            }
372        }
373
374        $tmpl->addContent("</select>
375            Желаемая дата доставки:<br>
376            <input type='text' name='delivery_date' value='{$this->dop_data['delivery_date']}' style='width: 100%'><br>");
377        if (@$this->dop_data['delivery_address']) {
378            $tmpl->addContent("<b>Адрес доставки: </b>{$this->dop_data['delivery_address']}<br>");
379        }
380
381        $tmpl->addContent("<br><hr>
382            Статус (может меняться автоматически):<br>
383            <select name='status'>");
384        if (@$this->dop_data['status'] == '') {
385            $tmpl->addContent("<option value=''>Не задан</option>");
386        }
387        $ldo = new \Models\LDO\zstatuses();
388        $status_list = $ldo->getData();
389        foreach ($status_list as $id => $name) {
390            $s = (@$this->dop_data['status'] == $id) ? 'selected' : '';
391            $tmpl->addContent("<option value='$id' $s>$name</option>");
392        }
393
394        $tmpl->addContent("</select><br><hr>");
395       
396       
397        $ldo = new \Models\LDO\workernames();
398        $ret = \widgets::getEscapedSelect('worker_id', $ldo->getData(), $this->dop_data['worker_id'], 'не назначен');
399       
400        $tmpl->addContent("Сотрудник:<br>$ret");       
401    }
402
403    /// Сохранение расширенных свойств документа
404    function DopSave() {
405        $new_data = array(
406            'status' => request('status'),
407            'delivery' => rcvint('delivery'),
408            'delivery_region' => rcvint('delivery_region'),
409            'delivery_date' => request('delivery_date'),
410            'buyer_email' => request('buyer_email'),
411            'buyer_phone' => request('buyer_phone'),
412            'worker_id' => request('worker_id'),
413        );
414        $old_data = array_intersect_key($new_data, $this->dop_data);
415
416        if ($this->id && @$old_data['status'] != $new_data['status']) {
417            $this->sentZEvent('cstatus:' . $new_data['status']);
418        }
419        $this->setDopDataA($new_data);
420    }
421
422    /// Выполнение дополнительных проверок доступа для проведения документа
423    public function extendedApplyAclCheck() {
424        $acl_obj = ['store.global', 'store.'.$this->doc_data['sklad']];     
425        if (!\acl::testAccess($acl_obj, \acl::APPLY)) {
426           $d_start = date_day(time());
427            $d_end = $d_start + 60 * 60 * 24 - 1;
428            if (!\acl::testAccess($acl_obj, \acl::TODAY_APPLY)) {
429                throw new \AccessException('Не достаточно привилегий для проведения документа с выбранным складом '.$this->doc_data['sklad']);
430            } elseif ($this->doc_data['date'] < $d_start || $this->doc_data['date'] > $d_end) {
431                throw new \AccessException('Не достаточно привилегий для проведения документа с выбранным складом '.$this->doc_data['sklad'].' произвольной датой');
432            }
433        }
434        parent::extendedApplyAclCheck();
435    }
436   
437    /// Выполнение дополнительных проверок доступа для отмены документа
438    public function extendedCancelAclCheck() {
439        $acl_obj = ['store.global', 'store.'.$this->doc_data['sklad']];     
440        if (!\acl::testAccess($acl_obj, \acl::CANCEL)) {
441           $d_start = date_day(time());
442            $d_end = $d_start + 60 * 60 * 24 - 1;
443            if (!\acl::testAccess($acl_obj, \acl::TODAY_CANCEL)) {
444                throw new \AccessException('Не достаточно привилегий для отмены проведения документа с выбранным складом '.$this->doc_data['sklad']);
445            } elseif ($this->doc_data['date'] < $d_start || $this->doc_data['date'] > $d_end) {
446                throw new \AccessException('Не достаточно привилегий для отмены проведения документа с выбранным складом '.$this->doc_data['sklad'].' произвольной датой');
447            }
448        }
449        parent::extendedCancelAclCheck();
450    }
451       
452    /// Провести документ
453    /// @param silent Не менять отметку проведения
454    function docApply($silent = 0) {
455        if (!$silent) {
456            $this->setDopData('reserved', '1');
457        }       
458        $this->setReserves();
459        if ($silent) {
460            return;
461        }
462        $this->fixPrice();
463        if (!$this->isAltNumUnique()) {
464            throw new Exception("Номер документа не уникален!");
465        }
466        parent::docApply($silent);
467    }
468           
469    /// Отменить проведение документа
470    function docCancel() {
471        global $db;
472        if (!$this->doc_data['ok']) {
473            throw new Exception('Документ не проведён!');
474        }       
475        $db->update('doc_list', $this->id, 'ok', 0);
476        $this->doc_data['ok'] = 0;
477        $this->unsetReserves();
478        $this->sentZEvent('cancel');
479    }
480   
481        /// Загружает счётчики резервов для текущей заявки
482    protected function getReserves() {
483        global $db;
484        $ret = array();
485        if(!$this->getDopData('reserved')) {
486            return $ret;
487        }
488        $res = $db->query("SELECT `doc_list_pos`.`tovar` AS `pos_id`, `doc_list_pos`.`cnt`
489            FROM `doc_list_pos`
490            LEFT JOIN `doc_base` ON `doc_base`.`id`=`doc_list_pos`.`tovar`
491            WHERE `doc_list_pos`.`doc`='{$this->id}'");
492        while($line = $res->fetch_assoc()) {
493            $c_res = $db->query("SELECT SUM(`doc_list_pos`.`cnt`)"
494                . " FROM `doc_list_pos`"
495                . " INNER JOIN `doc_list` ON `doc_list`.`id`=`doc_list_pos`.`doc`"
496                . " WHERE `doc_list_pos`.`tovar` = '{$line['pos_id']}' "
497                    . " AND `doc_list`.`type`=2 AND `doc_list`.`ok`>0 AND `doc_list`.`mark_del`=0 AND `doc_list`.`p_doc`='{$this->id}'"
498                );
499            if($c_res->num_rows) {
500                list($nr_cnt) = $c_res->fetch_row();
501                if(!$nr_cnt) {
502                    $nr_cnt = 0;
503                }
504            }
505            else {
506                $nr_cnt = 0;
507            }
508           
509            $reserve = $line['cnt'] - $nr_cnt;
510            if($reserve>0) {
511                $ret[$line['pos_id']] = $reserve;
512            }
513        }
514        return $ret; 
515    }
516
517    protected function unsetReserves() {
518        global $db;
519        $reserves = $this->getReserves();
520        foreach($reserves as $pos_id => $reserve) {
521            $db->query("INSERT INTO `doc_base_dop` (`id`, `reserve`) VALUES ($pos_id, '$reserve')
522                ON DUPLICATE KEY UPDATE `reserve`=`reserve`-VALUES(`reserve`)");
523        }       
524    }
525   
526    protected function setReserves() {
527        global $db;
528        $reserves = $this->getReserves();
529        foreach($reserves as $pos_id => $reserve) {
530            $db->query("INSERT INTO `doc_base_dop` (`id`, `reserve`) VALUES ($pos_id, '$reserve')
531                ON DUPLICATE KEY UPDATE `reserve`=`reserve`+VALUES(`reserve`)");
532        }       
533    } 
534
535    /**
536     * Получить список документов, которые можно создать на основе этого
537     * @return array Список документов
538     */
539    public function getMorphList() {
540        $morphs = array(
541            'r_all' =>      ['name'=>'r_all', 'document' => 'realizaciya', 'viewname' => 'Реализация (все товары)', ],
542            'r_partial' =>  ['name'=>'r_partial', 'document' => 'realizaciya', 'viewname' => 'Реализация (неотгруженные)', ],
543            'pko' =>        ['name'=>'pko',  'document' => 'pko',         'viewname' => 'Приходный кассовый ордер', ],
544            'pbank' =>      ['name'=>'pbank',  'document' => 'pbank',       'viewname' => 'Приход средств в банк', ],
545            'realiz_op' =>  ['name'=>'realiz_op', 'document' => 'realiz_op',   'viewname' => 'Оперативная реализация', ],
546            'zayavka' =>    ['name'=>'zayavka',  'document' => 'zayavka',     'viewname' => 'Копия заявки', ],
547            'specific' =>   ['name'=>'specific', 'document' => 'specific',    'viewname' => 'Спецификация (не используй здесь)', ],
548        );
549        return $morphs;
550    }
551
552    /** Сформировать реализацию со всеми товарами на основе этого документа
553     *
554     * @return \doc_Realizaciya
555     */
556    protected function morphTo_r_all() {       
557        $new_doc = new \doc_Realizaciya();
558        $new_doc->createFromP($this);
559        $data = [
560            'cena' => $this->dop_data['cena'],
561            'platelshik' => $this->doc_data['agent'],
562            'gruzop' => $this->doc_data['agent'],
563            'ishop' => $this->dop_data['ishop'],
564            'received' => 0,
565        ];
566        $new_doc->setDopDataA($data);
567        $this->sentZEvent('morph_realizaciya');
568        return $new_doc;
569    }
570   
571    /** Сформировать реализацию с неотгруженными товарами на основе этого документа
572     *
573     * @return \doc_Realizaciya
574     */
575    protected function morphTo_r_partial() {
576        $new_doc = new \doc_Realizaciya();
577        $new_doc->createFromPDiff($this);
578        $data = [
579            'cena' => $this->dop_data['cena'],
580            'platelshik' => $this->doc_data['agent'],
581            'gruzop' => $this->doc_data['agent'],
582            'ishop' => $this->dop_data['ishop'],
583            'received' => 0,
584        ];
585        $new_doc->setDopDataA($data);
586        $this->sentZEvent('morph_realizaciya');
587        return $new_doc;
588    }
589   
590    /**
591     * Сформировать приходный кассовый ордер
592     */
593    protected function morphTo_pko() {
594        global $db;       
595        $this->recalcSum();
596        $base = $this->Otgruzka();
597        if (!$base) {
598            throw new \Exception("Не удалось создать подчинённый документ");
599        }
600        $new_doc = new doc_Pko();
601        $doc_data = $this->doc_data;
602        $doc_data['p_doc'] = $base;
603        $new_doc->create($doc_data);
604        $new_doc->setDocData('kassa', 1);
605        $this->sentZEvent('morph_pko');
606        return $new_doc;       
607    }
608   
609    protected function morphTo_pbank() {
610        global $db;       
611        $this->recalcSum();
612        $base = $this->Otgruzka();
613        if (!$base) {
614            throw new Exception("Не удалось создать подчинённый документ!");
615        }       
616        $new_doc = new doc_PBank();
617        $doc_data = $this->doc_data;
618        $doc_data['p_doc'] = $base;
619        $new_doc->create($doc_data);
620        $this->sentZEvent('morph_pbank');
621        return $new_doc;       
622    }
623
624    protected function morphTo_realiz_op() {
625        $new_doc = new doc_Realiz_op();
626        $new_doc->createFromP($this);
627        $new_doc->setDopData('ishop', $this->dop_data['ishop']);
628        $this->sentZEvent('morph_oprealizaciya');
629        return $new_doc;
630    }
631   
632    protected function morphTo_zayavka() {
633        $new_doc = new doc_zayavka();
634        $new_doc->createFromP($this);
635        $new_doc->setDopData('cena', $this->dop_data['cena']);
636        return $new_doc;
637    }
638   
639    protected function morphTo_specific() {
640        $new_doc = new doc_Specific();
641        $new_doc->createFromP($this);
642        $new_doc->setDopData('cena', $this->dop_data['cena']);
643        return $new_doc;
644    } 
645   
646    protected function sendNotificationMessage() {
647        global $tmpl;
648        try {
649            \acl::accessGuard('doc.' . $this->typename, \acl::UPDATE);
650            $text = request('text');
651            $send = false;
652            if (request('sms')) {
653                $send |= $this->sendSMSNotify($text);
654            }
655            if (request('mail')) {
656                $send |= $this->sendEmailNotify($text);
657               }
658            if(!$send) {
659                throw new Exception('Не удалось отправить сообщение.');
660            }
661            $tmpl->setContent("{\"object\":\"send_message\",\"response\":\"success\"}");
662        } catch (Exception $e) {
663            $ret_data = array(
664                'object' => 'send_message',
665                'response' => 'error',
666                'errorcode' => $e->getCode(),
667                'errormessage' => $e->getMessage()
668            );
669            $tmpl->setContent( json_encode($ret_data, JSON_UNESCAPED_UNICODE) );
670        }
671    }
672   
673    protected function sendPie() {
674        global $tmpl;
675        try {
676            \acl::accessGuard('doc.' . $this->typename, \acl::UPDATE);
677            $this->sendEmailNotify(\cfg::get('doc', 'pie'));
678            $this->setDopData('pie', 1);
679            $tmpl->setContent("{\"object\":\"send_pie\",\"response\":\"success\"}");
680        } catch (Exception $e) {
681            $ret_data = array(
682                'object' => 'send_pie',
683                'response' => 'error',
684                'errorcode' => $e->getCode(),
685                'errormessage' => $e->getMessage()
686            );
687            $tmpl->setContent(json_encode($ret_data, JSON_UNESCAPED_UNICODE));
688        }
689    }
690   
691    protected function rewriteposList() {
692        global $db;
693        \acl::accessGuard('doc.' . $this->typename, \acl::UPDATE);
694        $db->startTransaction();
695        $db->query("DELETE FROM `doc_list_pos` WHERE `doc`='{$this->id}'");
696        $res = $db->query("SELECT `id` FROM `doc_list` WHERE `p_doc`='{$this->id}'");
697        $docs = "`doc`='-1'";
698        while ($nxt = $res->fetch_row()) {
699            $docs.=" OR `doc`='$nxt[0]'";
700        }
701        $res = $db->query("SELECT `doc`, `tovar`, SUM(`cnt`) AS `cnt`, `gtd`, `comm`, `cost`, `page` FROM `doc_list_pos` WHERE $docs GROUP BY `tovar`");
702        while ($line = $res->fetch_assoc()) {
703            $line['doc'] = $this->id;
704            $db->insertA('doc_list_pos', $line);
705        }
706        doc_log("REWRITE", "", 'doc', $this->id);
707        $db->commit();
708        header("location: /doc.php?mode=body&doc=" . $this->id);
709    }
710   
711    protected function toggleReserve() {
712        global $tmpl, $db;
713        try {
714            \acl::accessGuard('doc.' . $this->typename, \acl::UPDATE);
715            $db->startTransaction();
716            $new_res = $this->getDopData('reserved', 0)?0:1;
717            if($this->doc_data['ok']) {
718                $this->unsetReserves();
719            }
720            $this->setDopData('reserved', $new_res);
721            if($this->doc_data['ok']) {
722                $this->setReserves();
723            }
724            $db->commit();
725            $state = $new_res?'разрешены':'сняты';
726            $tmpl->setContent("{\"object\":\"togglereserve\",\"response\":\"success\",\"reserved\":\"$new_res\"}");
727            $ret_data = array(
728                'object' => 'togglereserve',
729                'response' => 'success',
730                'reserved' => $new_res,
731                'message' => 'Резервы '.$state
732            );
733            $tmpl->setContent(json_encode($ret_data, JSON_UNESCAPED_UNICODE));
734        } catch (Exception $e) {
735            $ret_data = array(
736                'object' => 'togglereserve',
737                'response' => 'error',
738                'errorcode' => $e->getCode(),
739                'errormessage' => $e->getMessage()
740            );
741            $tmpl->setContent(json_encode($ret_data, JSON_UNESCAPED_UNICODE));
742        }       
743    }
744    function Service() {
745        global $tmpl, $CONFIG, $db;
746        $tmpl->ajax = 1;
747        $opt = request('opt');
748        $pos = rcvint('pos');
749       
750        switch($opt) {
751            case 'pmsg':
752                $this->sendNotificationMessage();
753                break;
754            case 'rewrite':
755                $this->rewriteposList();
756                break;
757            case 'pie':
758                $this->sendPie();
759                break;
760            case 'togglereserve':
761                $this->toggleReserve();
762                break;
763            default:
764                parent::_Service($opt, $pos);
765        }
766    }
767
768    /// Отгрузить текущую заявку
769    function Otgruzka() {
770        $this->recalcSum();
771        $newdoc = new doc_Realizaciya();
772        $newdoc_id = $newdoc->createFromPdiff($this);
773        $newdoc->setDopData('cena', $this->dop_data['cena']);
774        return $newdoc_id;
775    }
776
777}
Note: See TracBrowser for help on using the repository browser.