interface View
{
public function render($model = null);
public function content($model = null);
}
class Handler implements View {
public function content($module = null)
{
ob_start();
ob_end_clean();
// возврат значения
}
public function render($module = null)
{
// эхо вашего HTML
}
}
class MainHandler extends Handler {
// а тут реализуете что вам нужно.
}
<select name="my select" data-default-value="какое-то значение"></select>
SELECT_BUILD = {1:Знач1, 2:Знач2, и т.д.}
window.alert = function(text) { console.log(text); }
<?php
class InvoiceHandler
{
protected $db = null;
public function __construct($invoice)
{
$this->db = DBPool::me()->getLink();
self::Handler($invoice);
}
//TODO: ставить ждет оплату если стоит в новом заказе
private function Handler($invoice)
{
$db = $this->db;
$socket = array();
$structure = Utils1c::prepareStructure($invoice,'invoice');
// Усли инвойс поставлен на удаление, то и мы удалим инвойс из базы
if ($invoice['DeletionMark'] == true) {
$socket = array_merge($socket, self::deleteInvoiceFromCRM($invoice,$structure));
// Инвойс обновился или же создан новый. Необходимо проверить
} else {
// Делаем поиск в базе
$sth = self::findInvoiceDataFromCRM($invoice);
// 4. У нас есть привязка счета к какому-то заказу
if ($sth->rows())
{
// Выгружаем данные полностью
$crmData = $sth->fetchrowset('item_uuid');
$structure['debug'][] = 'найдено ' . count($crmData) . ' записей в базе по данному счету';
// 2. Удалим записи из invoice_data если там есть лишние
$socket = array_merge($socket, self::deleteInvoiceDataOnDeleteInERP($invoice,$crmData,$structure));
$structure['debug'][] = 'количество записей после уделания: ' . count($crmData);
// 3. Добавляем в invoice_data новые строки буз order_data_id, если их добавили через 1с
$socket = array_merge($socket, self::insertInvoiceDataOnNewRowInERP($invoice,$crmData,$structure));
// 4. Необходимо сравнить все позиции и обновить значения
$socket = array_merge($socket, self::compareInvoiceBetweenCRMandERP($invoice,$crmData,$structure));
} else {
$structure['debug'][] = 'У нас нет данных в order_data_id по данному счету';
}
}
$socket[] = Driver1c::SOCKET_MARKER.json_encode($structure, JSON_UNESCAPED_UNICODE);
new WebSocketClient($socket);
return;
}
private function deleteInvoiceFromCRM($invoice, &$structure)
{
$db = $this->db;
$socket = array();
$structure['action'] = "delete";
// Перед удалением проверить что у нас есть привязка и в случае наличи
// позиции заказов отметить как отмененные
$sth = $db->prepare("
DELETE FROM
invoices
USING
invoice_data
WHERE
invoices.invoice_uuid = invoice_data.invoice_uuid AND
invoices.invoice_uuid = ?
RETURNING
invoice_data.order_data_id,
invoices.order_id
");
$sth->execute($invoice['Ref']);
// Если инвойс сохраненный через CRM
if ( $sth->rows() ) {
$std = $db->prepare("UPDATE order_data SET status = ? WHERE order_data_id = ?");
while ($row = $sth->fetchrow()) {
$structure['order_id'] = $row['order_id'];
$structure['order_data'][] = array ($row['order_data_id'] => 'delete');
$std->execute(OrderState::CANCELED,$row['order_data_id']);
$socket[] = "Motion:change:".$row['order_data_id'].":".OrderState::CANCELED.":Status";
}
}
return $socket;
}
private function findInvoiceDataFromCRM($invoice)
{
$db = $this->db;
// Нам в первую очередь надо найти сам заказ и что инвойс к нашему заказу привязан
// поэтому джоиним инвойсы через номер заказа по uuid счета
// при этом также вытаскиваем то, что у нас должно или не должно быть в счете
$sth = $db->prepare
("
SELECT
i.invoice_number,
i.invoice_amount,
i.invoice_customer,
i.invoice_date,
timestamp ? AS date_check,
o.order_id,
id.order_data_id,
id.quantity,
id.price,
id.item_uuid
FROM
orders o
JOIN invoices i ON
i.order_id = o.order_id
JOIN invoice_data id ON
id.invoice_uuid = i.invoice_uuid
WHERE
i.invoice_uuid = ?
");
$sth->execute($invoice['Date'], $invoice['Ref']);
/* пример выборки
invoice_number | invoice_amount | invoice_customer | invoice_date | date_check | order_id | order_data_id | quantity | price | item_uuid
----------------+----------------+--------------------------------------+---------------------+------------------+----------+---------------+----------+-------+--------------------------------------
00000000073 | 493920 | bd63f5ba-55f1-11e5-5d98-0e459e882122 | 2017-03-02 01:51:35 | | 5110 | 10125 | 8 | 41160 | 76e80df8-5802-11e4-6686-0e459e882122
00000000073 | 493920 | bd63f5ba-55f1-11e5-5d98-0e459e882122 | 2017-03-02 01:51:35 | | 5110 | 10124 | 4 | 41160 | bde6a7ce-32c2-11e2-92a8-c692850d4a80
00000000073 | 493920 | bd63f5ba-55f1-11e5-5d98-0e459e882122 | 2017-03-02 01:51:35 | | 5110 | | 1 | 111 | e6b5251c-feb3-11e6-ef88-26a4bef88324
1. Пользоваетель добавляет инвойс через сайт, соответствие позициций заказа сохраняется через order_data_id, а то что в инвойсе через item_uuid
2. Если в 1с кто-то удаляет позицию, то мы в базе также обязаны удалить запись и из invoice_data
2.1 Алгоритм поиска записи:
2.1.1 получаем из этого запроса все текущие позиции с item_uuid
2.1.2. ищем такую запись в массиве $invoice['Товары']. Если не найдено, то строку нужно удалить
2.2 Процесс удаления:
2.2.1 перед удалением нам надо изменить в таблице order_data стаус на OrderState::CANCELED -> Отменен
2.2.2 затем удалить запись из invoice_data, так как в инвойсе этой строки не существует
3. Если в 1с кто-то добавляет позицию, а в CMR такой позиции нет, то мы должны будем ее добавить в invoice_data
3.1. Добавляем запись без указания order_data_id. Это будет говорить о том, что в счете есть такая позиция, а в CRM она никуда не привязана
3.2. Необходимо в веб сокете передать эту информацию и на сторое JS сделать информирование и обработку этих данных
4. Необходимо сравнить все позиции и высчитать новые значения
5. Пустая выборка означает, что полученный счет никуда не привязан
*/
return $sth;
}
private function deleteInvoiceDataOnDeleteInERP($invoice, &$data, &$structure)
{
$db = $this->db;
$socket = array();
$checkData = $data;
// пробегаем по всему товарам в счете и ансетим их в дате.
// по окончанию, если в дате что-то остается, то мы это и удалим
foreach ($invoice['Товары'] as $good) {
foreach ($checkData as $key => $row) {
if ($good['Номенклатура'] == $row['item_uuid']) {
unset($checkData[$key]);
}
}
}
if (count($checkData)) {
$sth = $db->prepare("UPDATE order_data SET status = ? WHERE order_data_id = ?");
$std = $db->prepare("DELETE FROM invoice_data WHERE item_uuid = ?");
foreach ($checkData as $key => $row) {
$sth->execute(OrderState::CANCELED,$row['order_data_id']);
if ($row['order_data_id']) {
$std->execute($row['item_uuid']);
$structure['order_data'][] = array ($row['order_data_id'] => 'canceled');
$socket[] = "Motion:change:".$row['order_data_id'].":".OrderState::CANCELED.":Status";
}
unset($data[$key]);
}
}
return $socket;
}
private function insertInvoiceDataOnNewRowInERP($invoice, $data, &$structure)
{
$db = $this->db;
$socket = array();
$order_id = null;
// пробегаем по всему позициям из даты и удаляем из в инвойсе
// подсчет, потому то мы могли все удалить в deleteInvoiceDataOnDeleteInERP
if (count($data)) {
foreach ($data as $row) {
$order_id = $row['order_id'];
foreach ($invoice['Товары'] as $key => $good) {
if ($row['item_uuid'] == $good['Номенклатура']) {
unset($invoice['Товары'][$key]);
}
}
}
if (count($invoice['Товары'])) {
foreach ($invoice['Товары'] as $row) {
$insert = array(
'invoice_uuid' => $invoice['Ref'],
'item_uuid' => $row['Номенклатура'],
'quantity' => $row['Количество'],
'price' => $row['Цена'],
);
$socket[] = Driver1c::SOCKET_MARKER."NewInvoiceItem:".$row['Номенклатура'].":order_id:".$order_id;
$db->insert("invoice_data",$insert);
}
}
}
return $socket;
}
private function compareInvoiceBetweenCRMandERP($invoice, $data, &$structure)
{
$db = $this->db;
$socket = array();
// подсчет, потому то мы могли все удалить в deleteInvoiceDataOnDeleteInERP
if (count($data)) {
$newArray = $data;
$shift = array_shift($newArray);
$structure['debug'][] = 'Номер заказа: ' . $shift['order_id'];
$difference = array();
if ($shift['invoice_number'] != $invoice['Number'] ){ $difference['invoice_number'] = $invoice['Number']; }
if ($shift['invoice_amount'] != $invoice['СуммаДокумента'] ){ $difference['invoice_amount'] = $invoice['СуммаДокумента']; }
if ($shift['invoice_customer'] != $invoice['Контрагент'] ){ $difference['invoice_customer'] = $invoice['Контрагент']; }
if ($shift['date_check'] != $shift['invoice_date'] ){ $difference['invoice_date'] = $invoice['Date']; }
if (count($difference))
{
// Ставим в структуру апдейт, что у нас произошли изменения
$structure['action'] = "update";
$structure['order_id'] = $shift['order_id'];
// Обновляем данные по инвойсу в базе
$db->update("invoices", $difference, "invoice_uuid = ?", $invoice['Ref']);
}
// теперь проверяем данные по каждой строчке
foreach ($data as $row) {
$structure['debug'][] = 'сравниваем каждый товар';
$item = Utils1c::findItemByUUID($invoice['Товары'], $row['item_uuid']);
if ($item == null) {
throw new Exception(
"Algorithm error, can't find row in ERP data : " . $row['item_uuid']
);
}
$difference = array();
if ($item['Количество'] != $row['quantity'] ){ $difference['quantity'] = $item['Количество']; }
if ($item['Цена'] != $row['price'] ){ $difference['price'] = $item['Цена']; }
//FIXME: а почпему мы изменяем только количество, когда и цену должны обновлять
if (count($difference)) {
$db->update("invoice_data", $difference, "order_data_id = ?", $row['order_data_id']);
if ($difference['quantity']) {
// Изменяем данные в самом заказе
$db->du("UPDATE order_data SET quantity = ? WHERE order_data_id = ?", $item['Количество'], $row['order_data_id']);
// Информируем через сокет, что количество изменилось
$socket[] = "Motion:change:{$row['order_data_id']}:{$item['Количество']}:Quantity";
}
$structure['order_data'][] = array ($row['order_data_id'] => 'update');
} else {
$structure['order_data'][] = array ($row['order_data_id'] => 'nochange');
$structure['debug'][] = "В счете количество={$item['Количество']}, в заказе {$row['quantity']}, изменения не требуются";
}
}
}
return $socket;
}
}
?>
SELECT
city_id,
city_name,
length(trim(city_name)),
CASE WHEN length(trim(city_name)) = 5 THEN 1
WHEN length(trim(city_name)) = 4 THEN 2
WHEN length(trim(city_name)) = 6 THEN 3
ELSE 1000 END AS ord
FROM
cities
ORDER BY
ord ASC
LIMIT 20;
city_id | city_name | length | ord
---------+-----------+--------+-----
9754 | Париж | 5 | 1
35180 | Актау | 5 | 1
35188 | Аягоз | 5 | 1
35178 | Аксай | 5 | 1
35195 | Есиль | 5 | 1
35238 | Темир | 5 | 1
35236 | Тараз | 5 | 1
35182 | Алга | 4 | 2
35249 | Эмба | 4 | 2
35194 | Есик | 4 | 2
35179 | Аксу | 4 | 2
35176 | Абай | 4 | 2
35184 | Арыс | 4 | 2
35177 | Акколь | 6 | 3
35214 | Ленгер | 6 | 3
35257 | Астана | 6 | 3
35222 | Риддер | 6 | 3
35250 | Шалкар | 6 | 3
35187 | Атырау | 6 | 3
35209 | Кентау | 6 | 3
(20 строк)
city_id | city_name | length | ord
---------+-----------+--------+-----
35238 | Темир | 5 | 1
35176 | Абай | 5 | 1
35184 | Арыс | 5 | 1
35180 | Актау | 5 | 1
9754 | Париж | 5 | 1
35178 | Аксай | 5 | 1
35195 | Есиль | 5 | 1
35188 | Аягоз | 5 | 1
35249 | Эмба | 4 | 2
35194 | Есик | 4 | 2
35182 | Алга | 4 | 2
35251 | Шар | 4 | 2
35179 | Аксу | 4 | 2
35243 | Ушарал | 6 | 3
35236 | Тараз | 6 | 3
35244 | Уштобе | 6 | 3
35234 | Талгар | 6 | 3
35257 | Астана | 6 | 3
35177 | Акколь | 6 | 3
35187 | Атырау | 6 | 3
(20 строк)