Multimag  0.2.992
document.php
См. документацию.
1 <?php
2 
3 // MultiMag v0.2 - Complex sales system
4 //
5 // Copyright (C) 2005-2018, BlackLight, TND Team, http://tndproject.org
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
16 //
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //
20 
22 class document {
23  protected $id = null;
24  protected $typename;
25  protected $viewname;
26 
27  protected $doc_data;
28  protected $dop_data;
29  protected $text_data = [];
30  protected $firm_vars;
31  protected $def_dop_data = [];
32 
33  protected $def_doc_data = [
34  'id' => 0,
35  'type' => 0,
36  'agent' => null,
37  'comment' => '',
38  'date' => 0,
39  'ok' => 0,
40  'sklad' => null,
41  'user' => null,
42  'altnum' => 0,
43  'subtype' => '',
44  'sum' => 0,
45  'nds' => 1,
46  'p_doc' => null,
47  'mark_del' => 0,
48  'kassa' => null,
49  'bank' => null,
50  'firm_id' => null,
51  'contract' => null,
52  'created' => 0,
53  'agent_name' => '',
54  'agent_fullname' => '',
55  'agent_dishonest' => 0,
56  'agent_comment' => ''
57  ];
58 
59  const DOC_TYPES = [
60  1 => "postuplenie",
61  2 => "realizaciya",
62  3 => "zayavka",
63  4 => "pbank",
64  5 => "rbank",
65  6 => "pko",
66  7 => "rko",
67  8 => "peremeshenie",
68  9 => "perkas",
69  10 => "doveren",
70  11 => "predlojenie",
71  12 => "v_puti",
72  13 => "kompredl",
73  14 => "dogovor",
74  15 => "realiz_op",
75  16 => "specific",
76  17 => "sborka",
77  18 => "kordolga",
78  19 => "korbonus",
79  20 => "realiz_bonus",
80  21 => "zsbor",
81  22 => "pko_oper",
82  23 => "permitout",
83  24 => "payinfo",
84  25 => "corract",
85  ];
86 
88  public function getId() {
89  return $this->id;
90  }
91 
93  public function getTypeName() {
94  return $this->typename;
95  }
96 
98  public function getViewName() {
99  return $this->viewname;
100  }
101 
103  static function getStandardSqlQuery() {
104  return "SELECT `a`.`id`, `a`.`type`, `a`.`agent`, `b`.`name` AS `agent_name`, `a`.`comment`, `a`.`date`, `a`.`ok`, `a`.`sklad`,
105  `a`.`user`, `a`.`altnum`, `a`.`subtype`, `a`.`sum`, `a`.`nds`, `a`.`p_doc`, `a`.`mark_del`, `a`.`kassa`, `a`.`bank`, `a`.`firm_id`,
106  `b`.`dishonest` AS `agent_dishonest`, `b`.`comment` AS `agent_comment`, `a`.`contract`, `a`.`created`, `b`.`fullname` AS `agent_fullname`
107  FROM `doc_list` AS `a`
108  LEFT JOIN `doc_agent` AS `b` ON `a`.`agent`=`b`.`id`";
109  }
110 
112  static function getClassNameFromType($type) {
113  return self::getClassNameFromName(self::getNameFromType($type));
114  }
115 
116  static public function getNameFromType($type) {
117  if(array_key_exists($type, self::DOC_TYPES)) {
118  return self::DOC_TYPES[$type];
119  }
120  return null;
121  }
122 
124  static function getClassNameFromName($doc_name) {
125  if(in_array($doc_name, self::DOC_TYPES)) {
126  return '\doc_'.$doc_name;
127  }
128  return null;
129  }
130 
131  static public function getViewNameFromName($doc_name) {
132  $classname = self::getClassNameFromName($doc_name);
133  if($classname == null) {
134  return null;
135  }
136  $doc = new $classname;
137  return $doc->viewname;
138  }
139 
141  static function getListTypes() {
142  return self::DOC_TYPES;
143  }
144 
146  static function getInstanceFromDb($doc_id) {
147  global $db;
148  settype($doc_id, 'int');
149  $res = $db->query( self::getStandardSqlQuery() . " WHERE `a`.`id`=$doc_id");
150  if (!$res->num_rows) {
151  throw new \NotFoundException("Документ не найден");
152  }
153  $doc_data = $res->fetch_assoc();
154  return self::getInstanceFromArray($doc_data);
155  }
156 
157  static function getInstanceFromType($type) {
158  $doc_class = self::getClassNameFromType($type);
159  if($doc_class==null) {
160  throw new \LogicException('Запрошенный тип документа ('.html_out($doc_class).') не зарегистрирован!');
161  }
162  return new $doc_class;
163  }
164 
165  static function getInstanceFromArray($doc_data) {
166  $doc = self::getInstanceFromType($doc_data['type']);
167  $doc->loadFromArray($doc_data);
168  return $doc;
169  }
170 
171  public function loadFromArray($doc_data) {
172  $this->id = $this->doc = (int) $doc_data['id'];
173  $this->doc_data = $doc_data;
174  $this->loadDopDataFromDb();
175  $this->loadTextDataFromDb();
176  }
177 
178  public function loadFromDb($doc_id) {
179  global $db;
180  $this->id = $this->doc = (int) $doc_id;
181  $res = $db->query( $this->getStandardSqlQuery() . " WHERE `a`.`id`={$this->id}");
182  if (!$res->num_rows) {
183  throw new \NotFoundException("Документ не найден");
184  }
185  $this->doc_data = $res->fetch_assoc();
186  $this->loadDopDataFromDb();
187  $this->loadTextDataFromDb();
188  }
189 
190  protected function loadDopDataFromDb() {
191  global $db;
192  $res = $db->query("SELECT `param`, `value` FROM `doc_dopdata` WHERE `doc`={$this->id}");
193  $this->dop_data = array();
194  while($nxt = $res->fetch_row()) {
195  $this->dop_data[$nxt[0]]=$nxt[1];
196  }
197  $this->firm_vars = $db->selectRow('doc_vars', $this->doc_data['firm_id']);
198 
199  if (method_exists($this, 'initDefDopData')) {
200  $this->initDefDopData();
201  }
202  $this->dop_data = array_merge($this->def_dop_data, $this->dop_data);
203  }
204 
205  protected function loadTextDataFromDb() {
206  global $db;
207  $res = $db->query("SELECT `param`, `value` FROM `doc_textdata` WHERE `doc_id`={$this->id}");
208  $this->text_data = array();
209  while($nxt = $res->fetch_row()) {
210  $this->text_data[$nxt[0]]=$nxt[1];
211  }
212  }
213 
219  protected function writeLogArray($action, $array) {
220  doc_log($action, json_encode($array, JSON_UNESCAPED_UNICODE), 'doc', $this->id);
221  }
222 
226  public function getDocData($name) {
227  if (isset($this->doc_data[$name])) {
228  return $this->doc_data[$name];
229  } else {
230  return '';
231  }
232  }
233 
235  public function getDocDataA() {
236  return $this->doc_data;
237  }
238 
240  public function setDocData($name, $value) {
241  global $db;
242  if(!isset($this->doc_data[$name])) {
243  $this->doc_data[$name] = null;
244  }
245  if ($this->id && $this->doc_data[$name] !== $value) {
246  $_name = $db->real_escape_string($name);
247  $db->update('doc_list', $this->id, $_name, $value);
248  $log_data = [$name => ['old'=>$this->doc_data[$name], 'new'=>$value] ];
249  $this->writeLogArray("UPDATE", $log_data);
250  }
251  $this->doc_data[$name] = $value;
252  }
253 
254  protected function setDocDataA($data) {
255  global $db;
256  $log_data = array();
257  $res = $db->query("SHOW COLUMNS FROM `doc_list`");
258  $col_array = array();
259  while ($nxt = $res->fetch_row()) {
260  $col_array[$nxt[0]] = $nxt[0];
261  }
262  unset($col_array['id']);
263  $i_data = array_intersect_key($this->doc_data, $col_array);
264 
265  if ($this->id) {
266  $to_write_data = array_diff_assoc($data, $i_data);
267  foreach ($to_write_data as $name => $value) {
268  if (!isset($this->doc_data[$name])) {
269  $log_data[$name] = ['new' => $value];
270  } else if ($this->doc_data[$name] !== $value) {
271  $log_data[$name] = ['old' => $this->doc_data[$name], 'new' => $value];
272  }
273  }
274  if (count($to_write_data) > 0) {
275  $db->updateA('doc_list', $this->id, $to_write_data);
276  $this->writeLogArray('UPDATE', $log_data);
277  }
278  } else {
279  $to_write_data = array_intersect_key($data, $i_data);
280  $this->id = $db->insertA('doc_list', $to_write_data);
281  $this->writeLogArray("CREATE", $to_write_data);
282  }
283  foreach ($to_write_data as $name => $value) {
284  $this->doc_data[$name] = $value;
285  }
286  return $this->id;
287  }
288 
292  public function getDopData($name) {
293  if (isset($this->dop_data[$name])) {
294  return $this->dop_data[$name];
295  } else {
296  return '';
297  }
298  }
299 
301  public function getDopDataA() {
302  return $this->dop_data;
303  }
304 
310  public function setDopData($name, $value) {
311  global $db;
312  if(!isset($this->dop_data[$name])) {
313  $this->dop_data[$name] = null;
314  }
315  if ($this->id && $this->dop_data[$name] !== $value) {
316  $_name = $db->real_escape_string($name);
317  $_value = $db->real_escape_string($value);
318  $db->query("REPLACE INTO `doc_dopdata` (`doc`,`param`,`value`) VALUES ( '{$this->id}' ,'$_name','$_value')");
319  $log_data = [$name => ['old'=>$this->dop_data[$name], 'new'=>$value] ];
320  $this->writeLogArray("UPDATE", $log_data);
321  }
322  $this->dop_data[$name] = $value;
323  return true;
324  }
325 
327  public function setDopDataA($array) {
328  global $db;
329  if ($this->id) {
330  $to_write_data = array_diff_assoc($array, $this->dop_data);
331  $log_data = array();
332  foreach ($to_write_data as $name => $value) {
333  if(!isset($this->dop_data[$name])) {
334  $this->dop_data[$name] = null;
335  }
336  $log_data[$name] = ['old'=>$this->dop_data[$name], 'new'=>$value];
337  $this->dop_data[$name] = $value;
338  }
339  if(count($to_write_data)>0) {
340  $db->replaceKA('doc_dopdata', 'doc', $this->id, $to_write_data);
341  $this->writeLogArray("UPDATE", $log_data);
342  }
343  }
344  }
345 
346  public function getTextData($name) {
347  if(isset($this->text_data[$name])) {
348  return $this->text_data[$name];
349  }
350  else {
351  return '';
352  }
353  }
354 
360  public function setTextData($name, $value) {
361  global $db;
362  if(!isset($this->text_data[$name])) {
363  $this->text_data[$name] = null;
364  }
365  if ($this->id && $this->text_data[$name] !== $value) {
366  $_name = $db->real_escape_string($name);
367  $_value = $db->real_escape_string($value);
368  $db->query("REPLACE INTO `doc_textdata` (`doc_id`,`param`,`value`) VALUES ( '{$this->id}' ,'$_name','$_value')");
369  $log_data = [$name => ['old'=>$this->text_data[$name], 'new'=>$value] ];
370  $this->writeLogArray("UPDATE", $log_data);
371  }
372  $this->text_data[$name] = $value;
373  return true;
374  }
375 
380  public function markForDelete() {
381  global $db;
382  if ($this->getDocData('mark_del')>0) { // Уже отмечен на удаление
383  return false;
384  }
385  if ($this->getDocData('ok')) {
386  throw new \Exception("Удаление проведённых документов не возможно!");
387  }
388  $res = $db->query("SELECT `id` FROM `doc_list` WHERE `p_doc`='{$this->id}' AND `mark_del`='0'");
389  if ($res->num_rows) {
390  throw new \Exception("Есть подчинённые документы без пометок на удаление. Удаление невозможно.");
391  }
392  $tim = time();
393  $db->update('doc_list', $this->id, 'mark_del', $tim);
394  $this->writeLogArray("MARKDELETE", []);
395  return $tim;
396  }
397 
398  public function unMarkDelete() {
399  global $db;
400  if ($this->getDocData('mark_del')==0) { // Не отмечен на удаление
401  return false;
402  }
403  $db->update('doc_list', $this->id, 'mark_del', 0);
404  $this->writeLogArray("UNMARKDELETE", []);
405  return true;
406  }
407 
409  function subordinate($p_doc) {
410  global $db;
411  if ($this->id == $p_doc) {
412  throw new \Exception('Нельзя связать с самим собой!');
413  }
414  if ($this->doc_data['ok']) {
415  throw new \Exception("Операция не допускается для проведённого документа!");
416  }
417  if ($p_doc != 0) {
418  // Проверяем существование документа
419  $res = $db->query("SELECT `p_doc` FROM `doc_list` WHERE `id`=$p_doc");
420  if (!$res->num_rows) {
421  throw new \Exception('Документ с ID ' . $p_doc . ' не найден.');
422  }
423  }
424  $this->setDocData('p_doc', $p_doc);
425  return true;
426  }
427 
429  public function getTextDataA() {
430  return $this->text_data;
431  }
432 
435  public function getMorphList() {
436  return [];
437  }
438 
440  public function morph($target) {
441  $ml = $this->getMorphList();
442  $info = null;
443  foreach($ml as $m_info) {
444  if($m_info['name']===$target) {
445  $info = $m_info;
446  break;
447  }
448  }
449  if(!$info) {
450  throw new \Exception("Неверный код целевого документа.");
451  }
452  $method = 'morphTo_'.$info['name'];
453  if(!method_exists($this, $method)) {
454  throw new \Exception("Метод морфинга не определён.");
455  }
456  return $this->$method($target);
457  }
458 
463  public function getParentInfo() {
464  global $db;
465  if(!$this->id || !$this->doc_data['p_doc']) {
466  return null;
467  }
468  $p_doc = intval($this->doc_data['p_doc']);
469  $res = $db->query("SELECT `id`, `type`, `altnum`, `subtype`, `date`, `ok`
470  FROM `doc_list`
471  WHERE `doc_list`.`id`='$p_doc'");
472  $line = $res->fetch_assoc();
473  if(!$line) {
474  return null;
475  }
476  $line['typename'] = self::getNameFromType($line['type']);
477  $line['viewname'] = self::getViewNameFromName($line['typename']);
478  unset($line['type']);
479  $line['date'] = date("d.m.Y H:i:s", $line['date']);
480  return $line;
481  }
482 
488  public function getSubordinatesInfo() {
489  global $db;
490  if(!$this->id) {
491  return null;
492  }
493  $ret = array();
494  $res = $db->query("SELECT `id`, `type`, `altnum`, `subtype`, `date`, `ok` FROM `doc_list`
495  WHERE `doc_list`.`p_doc`='{$this->id}'");
496  $pod = '';
497  while ($line = $res->fetch_assoc()) {
498  $line['typename'] = self::getNameFromType($line['type']);
499  $line['viewname'] = self::getViewNameFromName($line['typename']);
500  unset($line['type']);
501  $line['date'] = date("d.m.Y H:i:s", $line['date']);
502  $ret[] = $line;
503  }
504  return $ret;
505  }
506 
508  public function refillPosList($from_doc_id, $preclear = 0, $no_sum = 0) {
509  global $db;
510  if (!$this->sklad_editor_enable) {
511  throw new \Exception('Номенклатурная таблица в этом документе отсутствует!');
512  }
513 
514  include_once(\cfg::get('site', 'location') . "/include/doc.poseditor.php");
515  $poseditor = new \DocPosEditor($this);
516  $poseditor->setAllowNegativeCounts($this->allow_neg_cnt);
517 
518  if ($from_doc_id == 0) {
519  throw new \Exception("Документ с данными не задан");
520  }
521  $db->startTransaction();
522 
523  $res = $db->query("SELECT `id` FROM `doc_list` WHERE `id`=$from_doc_id");
524  if (!$res->num_rows) {
525  throw new \Exception("Документ с данными не найден");
526  }
527  if ($preclear) {
528  $db->query("DELETE FROM `doc_list_pos` WHERE `doc`='{$this->id}'");
529  }
530  $res = $db->query("SELECT `doc`, `tovar`, SUM(`cnt`) AS `cnt`, `gtd`, `comm`, `cost`, `page` FROM `doc_list_pos`"
531  . "WHERE `doc`=$from_doc_id AND `page`=0 GROUP BY `tovar`");
532  while ($line = $res->fetch_assoc()) {
533  if (!$no_sum) {
534  $poseditor->simpleIncrementPos($line['tovar'], $line['cost'], $line['cnt'], $line['comm']);
535  } else {
536  $poseditor->simpleRewritePos($line['tovar'], $line['cost'], $line['cnt'], $line['comm']);
537  }
538  }
539  $this->writeLogArray("REWRITE", []);
540  $db->commit();
541 
542  return true;
543  }
544 }
setDocData($name, $value)
Установить основной параметр документа
Definition: document.php:240
$res
Definition: fixer.php:178
static getInstanceFromArray($doc_data)
Definition: document.php:165
$def_dop_data
Список дополнительных параметров текущего документа со значениями по умолчанию
Definition: document.php:31
getDopData($name)
Получить значение дополнительного параметра документа. Вернёт пустую строку в случае отсутствия парам...
Definition: document.php:292
getMorphList()
Definition: document.php:435
static getInstanceFromType($type)
Definition: document.php:157
markForDelete()
Definition: document.php:380
getViewName()
Получить отображаемое имя документа
Definition: document.php:98
$firm_vars
информация с данными о фирме
Definition: document.php:30
html_out($data)
Обёртка над htmlentities.
Definition: core.php:249
writeLogArray($action, $array)
Definition: document.php:219
static getClassNameFromName($doc_name)
Получить имя класса документа по его имени
Definition: document.php:124
getTextData($name)
Definition: document.php:346
$dop_data
Дополнительные данные документа
Definition: document.php:28
static getStandardSqlQuery()
Получить стандартную строку запроса загрузки документа
Definition: document.php:103
getTypeName()
Получить кодовое имя типа документа
Definition: document.php:93
subordinate($p_doc)
Сделать документ потомком указанного документа
Definition: document.php:409
refillPosList($from_doc_id, $preclear=0, $no_sum=0)
Слияние или перезапись табличной части двух документов
Definition: document.php:508
static getNameFromType($type)
Definition: document.php:116
$line
Definition: priceload.php:39
static getInstanceFromDb($doc_id)
Definition: document.php:146
$doc_data
Основные данные документа
Definition: document.php:27
$db
getParentInfo()
Definition: document.php:463
$tim
Definition: resp_clear.php:27
setTextData($name, $value)
Definition: document.php:360
getDopDataA()
Получить все дополнительные параметры документа в виде ассоциативного массива
Definition: document.php:301
const DOC_TYPES
Definition: document.php:59
getDocDataA()
Получить все основные параметры документа в виде ассоциативного массива
Definition: document.php:235
Базовый класс документов
Definition: document.php:22
loadFromDb($doc_id)
Definition: document.php:178
setDopDataA($array)
Установить дополнительные данные текущего документа
Definition: document.php:327
const getId()
Получить ID документа
Definition: document.php:88
morph($target)
Создать подчинённый документ из текущего
Definition: document.php:440
$typename
Наименование типа документа (для контроля прав и пр.)
Definition: document.php:24
setDocDataA($data)
Definition: document.php:254
$data
Definition: api.php:27
$text_data
Дополнительные текстовые данные документа
Definition: document.php:29
$doc_id
Definition: test_doc.php:24
static getListTypes()
Получить спискок типов документов
Definition: document.php:141
static getViewNameFromName($doc_name)
Definition: document.php:131
loadTextDataFromDb()
Definition: document.php:205
$doc
Definition: doc.php:28
$action
Definition: api.php:26
loadDopDataFromDb()
Definition: document.php:190
static get($sect, $param, $default=null)
Definition: cfg.php:46
$def_doc_data
Definition: document.php:33
getTextDataA()
Получить все текстовые параметры документа в виде ассоциативного массива
Definition: document.php:429
setDopData($name, $value)
Definition: document.php:310
doc_log($motion, $desc, $object='', $object_id=0)
Definition: doc.core.php:278
getSubordinatesInfo()
Definition: document.php:488
$id
ID документа
Definition: document.php:23
unMarkDelete()
Definition: document.php:398
static getClassNameFromType($type)
Получить имя класса документа по его номеру типа
Definition: document.php:112
$viewname
Отображаемое название документа при просмотре и печати
Definition: document.php:25
loadFromArray($doc_data)
Definition: document.php:171
getDocData($name)
Получить значение основного параметра документа. Вернёт пустую строку в случае отсутствия параметра ...
Definition: document.php:226