i.priymenko преди 1 седмица
родител
ревизия
e125179033

+ 26
- 0
docs/api_specs/auth.md Целия файл

@@ -0,0 +1,26 @@
1
+#### Авторизация JWT-токен
2
+
3
+* JWT-токен
4
+* заголовок Authorization
5
+* алгоритм HS256
6
+
7
+пример
8
+```
9
+Authorization: Bearer XXXXXXXXXXX.XXXXXXXXXX.XXXXXXXXXX
10
+```
11
+
12
+Access-токен, payload:
13
+```json
14
+{
15
+	"sp_ref": string,
16
+	"exp": "2000-01-01T21:00:11"
17
+}
18
+```
19
+
20
+Refresh-токен: XXXXXXXXXXXXXXXXXXX
21
+
22
+#### Авторизация через куки
23
+* `mshop_access` - jwt token
24
+* `mshop_refresh`
25
+
26
+включен авто-refresh при наличии `mshop_refresh`

+ 170
- 0
docs/api_specs/mshop_refill.md Целия файл

@@ -0,0 +1,170 @@
1
+### Подтоварка, мини-приложение
2
+
3
+#### Описание
4
+
5
+Мобильное web-приложение, для проведения подтоварки в магазине.
6
+
7
+**Термины**
8
+
9
+* **Задание на подтоварку** (**task**) - это группа товаров, которые нужно вынести в торговый зал. 
10
+* **Товар** (**item**) - одиночный товар в подтоварке. Имеет флаг "done" (выполнено)
11
+
12
+**Функционал**
13
+
14
+1. **Форма "задание подтоварки"** - товары подтоварки.
15
+   Содержит:
16
+	* текстовый заголовок
17
+	* список товаров:
18
+		* картинка, артикул, наименование
19
+		* цвет, размер
20
+		* цена_план, цена_текущая, скидка, остаток
21
+		* количество к обработке (нужно подтоварить)
22
+		* переключатель выполнения
23
+    Действия:
24
+	* печать ценников (выбранный товар)
25
+	* фильтр по товарной группе, текстовый поиск
26
+	* сканирование
27
+	* выполнить выбранные позиции (done = true)
28
+
29
+### Авторизация
30
+
31
+см. описание [здесь](auth.md)
32
+
33
+> реализована на уровне proxypatcher
34
+
35
+
36
+### API
37
+
38
+#### Стандартный ответ API
39
+
40
+```json
41
+{
42
+	"result": true,
43
+	"message": "текст ошибки, если есть иначе пусто"
44
+}
45
+```
46
+
47
+### 1. Первая очередь методов
48
+-----
49
+
50
+#### 1.1 Получение задачи
51
+---
52
+
53
+##### GET /mshop/{dep}/refill/task
54
+
55
+**query-параметры:**
56
+
57
+* `task_id`: "task_id"
58
+
59
+> Значения для `task_id`:
60
+> * daily - за вчера и за сегодня (2 дня)
61
+> * week - за последнюю неделю
62
+> * YYYY-MM-DD/YYYY-MM-DD - за выбранный период
63
+
64
+* `filter_mod`: "by_sales | by_incoming"
65
+
66
+> Возможные значения
67
+> filter_mod=`by_sales` -> вернуть товары у которых поле `дата продажи` в отчете подтоварка не пустое
68
+> filter_mod=`by_incoming` -> вернуть товары у которых поле `дата поступления` в отчете подтоварка не пустое
69
+> filter_mod=* -> любые возможные другие значения не учитывать
70
+
71
+ответ (вернуть как JSON):
72
+
73
+```json
74
+{
75
+	"result": true,
76
+	"message": "",
77
+	"task": {
78
+		"id": "task_id",
79
+		"title": "Подтоварка м001",
80
+		"dep": "001",
81
+		"comment": "коммент",
82
+		"items": [
83
+			{
84
+				"id": "id позиции",
85
+				"product_id": "код товара для печати ценника",
86
+				"article": "123-091",
87
+				"color": "цвет",
88
+				"size": "размер",
89
+				"sector": "сектор",
90
+				"group": "группа",
91
+				"image": "https://.../112209-0.jpg",
92
+				"title": "ТАПОЧКИ",
93
+				"base_price": 1000,
94
+				"price": 800,
95
+				"disc": "20%",
96
+				"label_color": "Белый | Красный", 
97
+				"rest": 4,
98
+				"qty": 3,
99
+				"done": false,
100
+				"done_updated": "2026-01-01 12:21:11"
101
+			}
102
+		]
103
+	}
104
+}
105
+```
106
+
107
+
108
+#### 1.2 Обновление состояния элемента
109
+---
110
+
111
+#### POST /mshop/{dep}/refill/update_item
112
+
113
+**query-параметры:**
114
+
115
+* `task_id`: "task_id"
116
+* `item_id`: "item_id"
117
+
118
+REQUEST BODY
119
+
120
+```json
121
+{
122
+	"done": true
123
+}
124
+```
125
+
126
+> done: true | false
127
+
128
+***ответ:***
129
+
130
+```json
131
+{
132
+	"result": true,
133
+	"message": "",
134
+	"update": {
135
+		"items": [
136
+			{
137
+				"id": "item_id",
138
+				"done": true,
139
+				"done_updated": "2026-01-01 12:12:00"
140
+			}		
141
+		]
142
+	}
143
+}
144
+```
145
+
146
+В ответе есть блок update - фреймворк обновляет данные в списке по указанию бэка. `id` - ключ, остальные поля - новые значения которые нужно обновить.
147
+
148
+#### 1.3 Сканирование товара (поиск по коду, серии, шк)
149
+---
150
+
151
+#### GET /mshop/{dep}/refill/find_item
152
+
153
+**query-параметры:**
154
+* `task_id`: "task_id"
155
+* `code`: "код хар-ки | серия | шк | маркировка"
156
+
157
+ответ:
158
+```json
159
+{
160
+	"result": true,
161
+	"message": "",
162
+	"item_id": "id"
163
+}
164
+```
165
+
166
+* `result`: true | false
167
+* `message`: "" | "код не опознан" | "товар не в задании"
168
+* `item_id`: id позиции в списке товаров (соответствует task.items.id) если найден
169
+
170
+

+ 167
- 0
docs/api_specs/mshop_reprice.md Целия файл

@@ -0,0 +1,167 @@
1
+### Переоценка, мини-приложение
2
+
3
+#### Описание
4
+
5
+Мобильное web-приложение, для проведения переоценки в магазине.
6
+
7
+**Термины**
8
+
9
+* **Задание на переоценку** (**task**) - это группа товаров, которые нужно переоценить.
10
+* **Товар** (**item**) - одиночный товар в переоценке. Имеет флаг "done" (выполнено)
11
+
12
+**Функционал**
13
+
14
+1. **Форма "задание переоценки"** - товары переоценки.
15
+   Содержит:
16
+	* текстовый заголовок
17
+	* список товаров:
18
+		* картинка, артикул, наименование
19
+		* цвет, размер
20
+		* цена_план, цена_новая, скидка, остаток
21
+		* количество к обработке (совпадает с остатком)
22
+		* переключатель выполнения
23
+    Действия:
24
+	* печать ценников (выбранный товар)
25
+	* фильтр по товарной группе, текстовый поиск
26
+	* сканирование
27
+	* выполнить выбранные позиции (done = true)
28
+
29
+### Авторизация
30
+
31
+см. описание [здесь](auth.md)
32
+
33
+> реализована на уровне proxypatcher
34
+
35
+### API
36
+
37
+#### Стандартный ответ API
38
+
39
+```json
40
+{
41
+	"result": true,
42
+	"message": "текст ошибки, если есть иначе пусто"
43
+}
44
+```
45
+
46
+### 1. Первая очередь методов
47
+
48
+-----
49
+
50
+#### 1.1 Получение задачи
51
+
52
+---
53
+
54
+##### GET /mshop/{dep}/reprice/task
55
+
56
+**query-параметры:**
57
+
58
+* `task_id`: "task_id"
59
+
60
+> Значения для `task_id`:
61
+> * daily - за вчера и за сегодня (2 дня)
62
+> * week - за последнюю неделю
63
+> * YYYY-MM-DD/YYYY-MM-DD - за выбранный период 
64
+
65
+ответ (вернуть как JSON):
66
+
67
+```json
68
+{
69
+	"result": true,
70
+	"message": "",
71
+	"task": {
72
+		"id": "task_id",
73
+		"title": "Переоценка м001",
74
+		"dep": "001",
75
+		"comment": "коммент",
76
+		"items": [
77
+			{
78
+				"id": "id позиции",
79
+				"product_id": "код товара для печати ценника",
80
+				"article": "123-091",
81
+				"color": "цвет",
82
+				"size": "размер",
83
+				"sector": "сектор",
84
+				"group": "группа",
85
+				"image": "https://.../112209-0.jpg",
86
+				"title": "ТАПОЧКИ",
87
+				"base_price": 1000,
88
+				"price": 800,
89
+				"disc": "20%",
90
+				"label_color": "Белый | Красный", 
91
+				"rest": 4,
92
+				"qty": 4,
93
+				"done": false,
94
+				"done_updated": "2026-01-01 12:21:11"
95
+			}
96
+		]
97
+	}
98
+}
99
+```
100
+
101
+#### 1.2 Обновление состояния элемента
102
+
103
+---
104
+
105
+#### POST /mshop/{dep}/reprice/update_item
106
+
107
+**query-параметры:**
108
+
109
+* `task_id`: "task_id"
110
+* `item_id`: "item_id"
111
+
112
+REQUEST BODY
113
+
114
+```json
115
+{
116
+	"done": true
117
+}
118
+```
119
+
120
+> done: true | false
121
+
122
+***ответ:***
123
+
124
+```json
125
+{
126
+	"result": true,
127
+	"message": "",
128
+	"update": {
129
+		"items": [
130
+			{
131
+				"id": "item_id",
132
+				"done": true,
133
+				"done_updated": "2026-01-01 12:12:00"
134
+			}		
135
+		]
136
+	}
137
+}
138
+```
139
+
140
+> В ответе опциональный блок update - фреймворк обновляет данные в списке по указанию бэка. 
141
+> `id` - ключ, остальные поля - новые значения которые нужно обновить.
142
+
143
+#### 1.3 Сканирование товара (поиск по коду, серии, шк)
144
+
145
+---
146
+
147
+#### GET /mshop/{dep}/reprice/find_item
148
+
149
+**query-параметры:**
150
+* `task_id`: "task_id"
151
+* `code`: "код хар-ки | серия | шк | маркировка"
152
+
153
+ответ:
154
+```json
155
+{
156
+	"result": true,
157
+	"message": "",
158
+	"item_id": "id"
159
+}
160
+```
161
+
162
+* `result`: true | false
163
+* `message`: "" | "код не опознан" | "товар не в задании"
164
+* `item_id`: id позиции в списке товаров (соответствует task.items.id) если найден
165
+
166
+
167
+

+ 69
- 0
docs/api_specs/mshop_service.md Целия файл

@@ -0,0 +1,69 @@
1
+#### 1.1 Получение списка шаблонов ценника (варианты размеров)
2
+
3
+---
4
+
5
+##### GET /mshop/{dep}/service/label_templates
6
+
7
+ответ:
8
+
9
+```json
10
+{
11
+	"result": true,
12
+	"message": "",
13
+	"templates": ["sm", "md", "lg"]
14
+}
15
+
16
+```
17
+
18
+> "templates": ["sm", "md", "lg"] - наименования размеров приведены для примера.
19
+
20
+#### 1.2 Печать ценника
21
+
22
+---
23
+
24
+##### POST /mshop/{dep}/service/print_label
25
+
26
+**query-параметры:**
27
+
28
+* `product_id`: "series | code | barcode"
29
+* `count`: int
30
+* `template`: (опционально, если шаблоны предусмотрены)
31
+
32
+**ответ: стандартный**
33
+
34
+
35
+#### 1.3 Запрос информации по товару
36
+
37
+##### GET /mshop/{dep}/service/product_info
38
+
39
+**query-параметры:**
40
+
41
+* `product_id`: "series | code | barcode | marking code"
42
+
43
+**ответ:**
44
+
45
+```json
46
+{
47
+"result": true,
48
+"message": "",
49
+"product_info": {
50
+  "code": "код хар-ки",
51
+  "article": "123-091",
52
+  "title": "наименование товара",
53
+  "color": "цвет",
54
+  "size": "размер",
55
+  "price": 800,
56
+  "price_full": 1000,
57
+  "discount_title": "20%",
58
+  "label_color": "Белый | Красный",
59
+  "all_sizes": [
60
+    {
61
+      "size": "размер наименование",
62
+      "code": "код хар-ки товара с таким размером",
63
+      "all_codes": "код1:кол-во,код2:кол-во"
64
+    }
65
+  ]
66
+ }
67
+}
68
+```
69
+

+ 357
- 0
docs/api_specs/mshop_shippicker.md Целия файл

@@ -0,0 +1,357 @@
1
+## Порт приложения shop_job
2
+
3
+## Используемые схемы данных:
4
+
5
+#### 1. job_data
6
+```
7
+{
8
+  "_id": "6315990c0178dd8a83657b31",
9
+  "id": "125_12165",
10
+  "type": "ПОДТОВАРКА_ХАБ",
11
+  "number": "125-S12165",
12
+  "title": "Подтоварка из 125 в 111",
13
+  "date": "2022-09-05T11:42:39.000Z",
14
+  "from": "125",
15
+  "to": "111",
16
+  "store": "ТорговыйЗал",
17
+  "comment": "Ежедневная подтоварка из 125 в 111 ",
18
+  "user": {
19
+    "id": "b3eb970a-06a6-11ed-a98f-fa163e191731",
20
+    "title": "Линейцева В.В."
21
+  },
22
+  "items": {
23
+    "124610": {
24
+      "id": "124610",
25
+      "image": "https://media.saticogroup.com/media/marmalato/www/0/116242-0.jpg",
26
+      "image2": "https://media.saticogroup.com/media/marmalato/www/1/101-045.jpg",
27
+      "article": "101-045",
28
+      "color": "ЧЕРНЫЙ-БЕЛЫЙ-СЕРЕБРО",
29
+      "size": "XS/S",
30
+      "title": "РЕМЕНЬ",
31
+      "desc": "",
32
+      "qty": 1,
33
+      "codes": [
34
+        {
35
+          "code": "124610",
36
+          "limit": 1
37
+        }
38
+      ]
39
+    },
40
+    "132634": {
41
+      "id": "132634",
42
+      "image": "https://media.saticogroup.com/media/marmalato/www/0/128096-0.jpg",
43
+      "image2": "https://media.saticogroup.com/media/marmalato/www/1/235-012.jpg",
44
+      "article": "235-012",
45
+      "color": "БЕЖЕВЫЙ",
46
+      "size": "38",
47
+      "title": "БОСОНОЖКИ",
48
+      "desc": "",
49
+      "qty": 1,
50
+      "codes": [
51
+        {
52
+          "code": "SGTN333",
53
+          "limit": 1
54
+        },
55
+        {
56
+          "code": "SGTN493",
57
+          "limit": 1
58
+        },
59
+        {
60
+          "code": "SGTN779",
61
+          "limit": 1
62
+        },
63
+        {
64
+          "code": "SGTN875",
65
+          "limit": 1
66
+        }
67
+      ]
68
+    }
69
+  }
70
+}    
71
+```
72
+
73
+#### 2. job_state
74
+```json
75
+{
76
+  "job_id": "125_12165",
77
+  "state": "НОВЫЙ",
78
+  "current_pack_id": "125-S12165-1",
79
+  "opened": "2022-09-05T02:36:59.000Z",
80
+  "closed": null,
81
+  "updated": "2025-05-23T09:26:37.773Z",
82
+  "user": {
83
+    "id": "b3eb970a-06a6-11ed-a98f-fa163e191731",
84
+    "title": "Линейцева В.В."
85
+  },
86
+  "version": 11,
87
+  "auto_save": false,
88
+  "packs": {
89
+    "125-S12165-1": {
90
+      "pack_id": "125-S12165-1",
91
+      "items": {
92
+        "124610": {},
93
+        "129439": {
94
+          "129439": 1
95
+        },
96
+        "135213": {
97
+          "135213": 1
98
+        },
99
+        ...,
100
+        "135064,130194": {
101
+          "135064": 1
102
+        },
103
+        "132859,135047": {
104
+          "135047": 1
105
+        },
106
+      },
107
+      "state": "ЗАКРЫТА",
108
+      "user": {
109
+        "id": "b3eb970a-06a6-11ed-a98f-fa163e191731",
110
+        "title": "Линейцева В.В."
111
+      },
112
+      "opened": "2022-09-05T06:37:09.791Z",
113
+      "item_updates": {
114
+        "124610": "2022-09-05T14:32:35.594Z",
115
+        "129439": "2022-09-05T14:33:20.922Z",
116
+        "133480": "2022-09-05T06:45:07.390Z",
117
+        "135193": "2022-09-05T06:41:27.346Z",
118
+        ...
119
+        "135202": "2022-09-05T06:42:00.226Z",
120
+        "135213": "2022-09-05T06:42:28.544Z",
121
+        "135064,130194": "2022-09-05T15:22:15.303Z",
122
+        "132859,135047": "2022-09-05T15:22:59.674Z",
123
+        "134396,132254": "2022-09-05T15:24:44.566Z",
124
+        "134845,129456": "2022-09-05T15:25:27.555Z"
125
+      },
126
+      "updated": "2022-09-05T15:34:35.856Z",
127
+      "closed": "2022-09-05T15:34:35.856Z",
128
+      "confirmed": "2022-09-05T02:49:43.000Z"
129
+    },
130
+    "125-S12165-2": {
131
+      "pack_id": "125-S12165-2",
132
+      "items": {},
133
+      "state": "УДАЛЕНА",
134
+      "user": {
135
+        "id": "b3eb970a-06a6-11ed-a98f-fa163e191731",
136
+        "title": "Линейцева В.В."
137
+      },
138
+      "opened": "2022-09-05T15:28:40.345Z",
139
+      "item_updates": {
140
+        "124610": "2022-09-05T15:28:40.348Z"
141
+      },
142
+      "updated": "2022-09-05T15:28:40.348Z"
143
+    },
144
+    "125-S12165-3": {
145
+      "pack_id": "125-S12165-3",
146
+      "items": {
147
+        "124610": {
148
+          "124610": 1
149
+        },
150
+        "132029": {
151
+          "132029": 1
152
+        },
153
+        "132435": {
154
+          "SGFV243": 1
155
+        },
156
+        "132634": {
157
+          "SGTN493": 1
158
+        }
159
+      },
160
+      "state": "ОТКРЫТА",
161
+      "user": {
162
+        "id": "b3eb970a-06a6-11ed-a98f-fa163e191731",
163
+        "title": "Линейцева В.В."
164
+      },
165
+      "opened": "2025-05-23T05:46:57.990Z",
166
+      "item_updates": {
167
+        "124610": "2025-05-23T09:26:31.394Z",
168
+        "132435": "2025-05-23T09:26:34.188Z",
169
+        "132634": "2025-05-23T09:26:37.773Z"
170
+      },
171
+      "updated": "2025-05-23T09:26:37.773Z"
172
+    }
173
+  },
174
+  "current_item_id": "124610"
175
+}
176
+```
177
+
178
+## Текущие требования по ендпоинтам:
179
+
180
+### getState
181
+
182
+> получение стейта
183
+
184
+#### GET /mshop/{dep}/shippicker/state
185
+**query-параметры:**
186
+```
187
+	job_id: "job_id",
188
+```
189
+
190
+возврат:
191
+```json
192
+{
193
+	result: 1,
194
+	job_id: integer,
195
+	job_data: {
196
+		...
197
+	},
198
+	job_state: {
199
+		...
200
+	}
201
+}
202
+```
203
+
204
+### saveState
205
+
206
+> Сохранение стейта целиком
207
+
208
+#### POST /mshop/{dep}/shippicker/state
209
+**query-параметры:**
210
+```
211
+	job_id: "job_id",
212
+```
213
+
214
+тело:
215
+
216
+```json
217
+{
218
+	...job_state
219
+}
220
+```
221
+
222
+### saveItemCode
223
+> Сохранение выбранного кода для отгрузки
224
+#### POST  /mshop/{dep}/shippicker/update_item,
225
+**query-параметры:**
226
+```
227
+	job_id: "job_id",
228
+	pack_id: "pack_id"
229
+```
230
+тело:
231
+```json
232
+{
233
+	id: item.id,
234
+	code: code,
235
+	qty: integer,
236
+	date: date.now()
237
+}
238
+```
239
+> при удалении количество (qty) = 0
240
+
241
+### Частичные сохранения стейта
242
+
243
+#### saveCurrentPosition
244
+#### POST /mshop/{dep}/shippicker/state
245
+**query-параметры:**
246
+```
247
+	job_id: "job_id",
248
+```
249
+тело:
250
+```json
251
+{
252
+	current_item_id: str
253
+	current_pack_id: str
254
+}
255
+```
256
+
257
+#### toggleAutosave
258
+#### POST /mshop/{dep}/shippicker/state
259
+**query-параметры:**
260
+```
261
+	job_id: "job_id",
262
+```
263
+тело:
264
+```json
265
+{
266
+	auto_save: bool
267
+}
268
+```
269
+
270
+#### savePackState
271
+##### POST /mshop/{dep}/shippicker/pack_state
272
+**query-параметры:**
273
+```
274
+	job_id: "job_id",
275
+	pack_id: "pack_id"
276
+```
277
+тело:
278
+
279
+```json
280
+{
281
+  state: string (ОТКРЫТА, ЗАКРЫТА, УДАЛЕНА), 
282
+  date: now()
283
+}
284
+```
285
+
286
+## Новые методы
287
+
288
+### Список отгрузок (задач)
289
+#### GET /mshop/{dep}/shippicker/list
290
+
291
+**query-параметры** (опционально)
292
+```
293
+status=opened | closed (необязательный, default=opened)
294
+```
295
+
296
+возврат:
297
+
298
+```json
299
+{
300
+  result: true,
301
+  message: "",
302
+  tasks: [
303
+    {
304
+      id: 'job_id',
305
+      title: 'string',
306
+      comment: 'коммент',
307
+      closed: datetime, 
308
+      items_count: int,
309
+      items_done: int,
310
+      packs_count: int
311
+    }
312
+  ]
313
+}
314
+```
315
+
316
+### Печать этикетки для коробки
317
+#### POST /mshop/{dep}/shippicker/print_label
318
+
319
+**query-params**:
320
+* job_id
321
+* pack_id
322
+
323
+**возврат**:
324
+```json
325
+{
326
+  result: true,
327
+  message: ""
328
+}
329
+```
330
+
331
+### Закрытие задания
332
+##### POST /mshop/{dep}/shippicker/close_job
333
+**query-параметры:**
334
+```
335
+	job_id: "job_id",
336
+```
337
+**возврат**:
338
+```json
339
+{
340
+  result: true,
341
+  message: ""
342
+}
343
+```
344
+
345
+### Открытие задания
346
+##### POST /mshop/{dep}/shippicker/open_job
347
+**query-параметры:**
348
+```
349
+	job_id: "job_id",
350
+```
351
+**возврат**:
352
+```json
353
+{
354
+  result: true,
355
+  message: ""
356
+}
357
+```

+ 102
- 0
modules/mshop_api_module.spm Целия файл

@@ -0,0 +1,102 @@
1
+;path:[?query_path] 
2
+;method:[?query_method] 
3
+;query:[?$out::query]
4
+;body:[?$out::body]
5
+
6
+#proc mshop_api.init
7
+	#se mshop_state_table=mshop_state
8
+#endproc
9
+
10
+#proc mshop_api.load_state(id)
11
+	#src state
12
+	#r		
13
+		#call mshop_api.init_state_tables_sql
14
+	
15
+		select 
16
+			state,
17
+			Параметры
18
+		from [mshop_state_table]  where ref=@'[id]'@ and Приложение='[mshop_api.app]';
19
+	
20
+	#query 
21
+	#endsrc
22
+
23
+	#if {state.Параметры#size}
24
+		#out_load_from_var params,@state.Параметры
25
+		#dump_to_ex_params params
26
+		>{state.state}
27
+	#else
28
+		#call mshop_api.new_state($id)
29
+		>{{}}
30
+	#endif
31
+#endproc
32
+
33
+#proc mshop_api.init_tables_sql
34
+
35
+         CREATE TABLE IF NOT EXISTS [mshop_state_table]
36
+		 (
37
+               ССЫЛКА			int primary key auto_increment,
38
+			   ПРИЛОЖЕНИЕ		VARCHAR(50),
39
+			   REF				VARCHAR(40),
40
+			   ОТВЕТСТВЕННЫЙ	INT NOT NULL,
41
+			   ДАТА				DATETIME,
42
+			   ИЗМЕНЕН			DATETIME,
43
+			   ПАРАМЕТРЫ		VARCHAR(8128),
44
+			   STATE			MEDIUMTEXT,
45
+               KEY(ДАТА),
46
+               UNIQUE INDEX(REF)
47
+			   
48
+		 ) 
49
+
50
+#endproc
51
+
52
+#proc mshop_api.new_state(id)
53
+		@{
54
+			[#mshop_api.init_tables_sql];
55
+			insert into [mshop_state_table](ПРИЛОЖЕНИЕ,REF,ОТВЕТСТВЕННЫЙ,ДАТА,ИЗМЕНЕН,STATE) 
56
+				values(@'[mshop_api.app]'@,@'[id]'@,'[?user_ref]',NOW(),NOW(),'{{}}')			
57
+		}@
58
+#endproc
59
+
60
+#proc mshop_api.save_state(id,state_obj,vars)
61
+
62
+		@{[#mshop_api.init_tables_sql]}@
63
+	
64
+		#out_save params
65
+		#o params
66
+		#r
67
+		#for param=([vars])
68
+			#ex_params_dump [var]*
69
+		#endfor
70
+		#out_restore params
71
+		@{	
72
+			update [mshop_state_table] set 
73
+				STATE=@'[state_obj]'@ ,
74
+				ИЗМЕНЕН=NOW(),
75
+				Параметры=@'[$out::params]'@
76
+			where ref=@'[id]'@ and Приложение='[mshop_api.app]';
77
+		}@
78
+#endproc
79
+
80
+
81
+#proc mshop_api.query
82
+		; разбор пути /app/procname
83
+	#json_pretty 0
84
+	#v (empty,app,procname|/)=[?query_path]
85
+	#se j:result={{}}
86
+	#se mshop_api.app=[app]
87
+	#try
88
+	
89
+		#include_module mshop_[app]_module
90
+		#v j:query=[$out::query]
91
+		#v j:body=[$out::body]
92
+		#v user_ref=@{select ссылка from spravochniki_sotrudniki where ref=@'[j:body.?access_payload.sp_ref]'@ }@
93
+		#call mshop_[app].[query_method].[procname]
94
+
95
+	#catch
96
+	
97
+		#se j:result={{"result":false,message:"[$f::json_quote($%exception.msg)]"}}
98
+	
99
+	#endtry
100
+	
101
+[j:result]
102
+#endproc

+ 362
- 0
modules/mshop_refill_module.spm Целия файл

@@ -0,0 +1,362 @@
1
+#block
2
+/*
3
+{
4
+	"result": true,
5
+	"message": "",
6
+	"task": {
7
+		"id": "task_id",
8
+		"title": "Подтоварка м001",
9
+		"dep": "001",
10
+		"comment": "коммент",
11
+		"items": [
12
+			{
13
+				"id": "xar.Ссылка", (нужно тк фреймворк берет это поле и отдает для update_item)
14
+				"product_id": "xar.Ссылка",
15
+				"article": "123-091",
16
+				"color": "цвет",
17
+				"size": "размер",
18
+				"sector": "сектор",
19
+				"group": "группа",
20
+				"image": "https://.../112209-0.jpg",
21
+				"title": "ТАПОЧКИ",
22
+				"base_price": 1000,
23
+				"price": 800,
24
+				"disc": "20%",
25
+				"label_color": "Белый | Красный", 
26
+				"rest": 4,
27
+				"qty": 3,
28
+				"done": false
29
+				"done_updated":"2026-01-01 yyyy-mm-dd"
30
+			}
31
+		]
32
+	}
33
+}
34
+*/
35
+#endblock
36
+
37
+#proc mshop_refill.sql_query
38
+
39
+	#se form_date=[$f::now()]
40
+	#se DateTo=@{SELECT Date_format('[form_date]', '%Y.%m.%d 23:59:59')}@
41
+	#se min_date=@{select DATE_SUB('[DateTo]', interval 7 day )}@
42
+	#se DateFrom=@{SELECT Date_format(DATE_SUB('[DateTo]', INTERVAL 1 DAY), '%Y.%m.%d 00:00:00')}@
43
+	#if !$report_ref
44
+		#se report_ref=@{SELECT UUID_SHORT();}@
45
+	#endif
46
+
47
+	#globalobjs_get Dep.Код
48
+	#se Подразделение.код=[dep.код]
49
+
50
+	#se PriceType=@{select tp.ссылка from spravochniki_tipicen as tp inner join spravochniki_podrazdeleniya as dep on dep.ТипЦен=tp.ссылка where dep.Код='[Подразделение.Код]'}@
51
+	#se BasePriceType=@{select IFNULL(БазовыйТипЦен,0) from spravochniki_tipicen as tp inner join spravochniki_podrazdeleniya as dep on dep.ТипЦен=tp.ссылка where dep.Код='[Подразделение.Код]'}@
52
+	#se PlanPriceType=@{select Ссылка from spravochniki_tipicen as tp  where Наименование='РозницаПлан'}@
53
+
54
+	#se OPT_SELECT_FIELDS=@!!@
55
+
56
+	#se EXTRA_WHERE=AND ((rozdv.ДАТА >= pod.ДатаПодтоварки OR pod.ДатаПодтоварки IS NULL) OR (pod.ДатаПодтоварки >= DATE_SUB(NOW(), INTERVAL 24 HOUR)))
57
+	#se HAVING_FILTER=
58
+	#if $filter_sql
59
+		#if [filter_sql]=by_sales
60
+			#se HAVING_FILTER=HAVING ДатаПродажи IS NOT NULL
61
+		#endif
62
+		#if [filter_sql]=by_incoming
63
+			#se HAVING_FILTER=HAVING ДатаПоступления IS NOT NULL
64
+		#endif
65
+	#endif
66
+
67
+	#include_module refill_sql
68
+	[#refill_sql.build_query]
69
+
70
+#endproc
71
+
72
+#proc mshop_refill.get.list
73
+	/*не актуально*/
74
+
75
+	#src stats
76
+	#r
77
+
78
+		select count(distinct IF(IFNULL(LENGTH(`Подтоварить`),0)>0 AND `Дата подтоварки`>date(date_sub(now(),interval 6 hour)),Характеристика,NULL))   as items_done,
79
+				count(distinct IF(IFNULL(LENGTH(`Подтоварить`),0)=0 OR `Дата подтоварки`>date(date_sub(now(),interval 6 hour)),Характеристика,NULL))   as items
80
+		from ([#mshop_refill.sql_query]) as qq
81
+
82
+	#query
83
+	#endsrc
84
+
85
+	#se j:result={{"result":true,"message":""}}
86
+
87
+	#v j:task={{}}
88
+	#v j:task.id="torg_zal"
89
+	#v j:task.title="ПОДТОВАРКА ТЗ"
90
+	#v j:task.created="[$f::now]"
91
+	#v j:task.comment="Подтоварка торгового зала"
92
+
93
+	#if {stats}
94
+		#v j:task.items_count={stats.items}
95
+		#v j:task.items_done={stats.items_done}
96
+	#else
97
+		#v j:task.items_count=0
98
+		#v j:task.items_done=0
99
+	#endif
100
+
101
+	#se j:result.tasks=[[ [j:task] ]]
102
+
103
+#endproc
104
+
105
+#block
106
+/*
107
+
108
+{
109
+	result: true,
110
+	message: '',
111
+	task: {
112
+		id: 'task_id',
113
+		title: 'ПРЕОЦЕНКА м001',
114
+		created: '01.01.2020',
115
+		number: '012-022',
116
+		dep: '001',
117
+		price_type: 'тип цены',
118
+		label_color: '#',
119
+		comment: 'коммент',
120
+		items: [
121
+		  {
122
+		    id: 1,
123
+		    article: '123-091',
124
+		    color: 'цвет',
125
+		    size: 'размер',
126
+		    group: 'группа1',
127
+		    image: 'https://.../112209-0.jpg',
128
+		    title: 'ТАПОЧКИ',
129
+		    price: 1290,
130
+		    qty: 3,
131
+		    done: false
132
+		  },
133
+		]
134
+	}
135
+}
136
+
137
+*/
138
+#endblock
139
+
140
+#proc mshop_refill.get.task(task_id)
141
+
142
+	#se filter_sql=[?j:query.filter_mod]
143
+
144
+	#src items_sql
145
+	#r
146
+
147
+	[#mshop_refill.sql_query]
148
+
149
+	#query
150
+	#endsrc
151
+
152
+	#globalobjs_get Dep.Код
153
+
154
+	#se j:result={{"result":true,"message":""}}
155
+
156
+	#v DF=@{select Date_format('[DateFrom]', '%d.%m.%Y')}@
157
+	#v DT=@{select Date_format('[DateTo]', '%d.%m.%Y')}@
158
+
159
+	#v j:task={{}}
160
+	#v j:task.id="torg_zal"
161
+	#v j:task.title="ПОДТОВАРКА [dep.код]"
162
+	#v j:task.dep="[dep.код]"
163
+	#v j:task.comment="За период с [DF] по [DT]"
164
+
165
+	#v j:items=[[ ]]
166
+	#foreach items_sql
167
+
168
+		#v j:item={{}}
169
+
170
+		#v j:item.id="{items_sql.tov_id}"
171
+		#v j:item.product_id="{items_sql.product_id}"
172
+		#v j:item.article="{items_sql.Артикул}"
173
+		#v j:item.color="{items_sql.Цвет}"
174
+		#v j:item.size="{items_sql.Размер}"
175
+		#v j:item.sector="{items_sql.Сектор}"
176
+		#v j:item.group="{items_sql.Группа}"
177
+		#v j:item.image="{items_sql.Фото}"
178
+		#v j:item.title="{items_sql.Наименование}"
179
+		#v j:item.base_price="{items_sql.Цена план}"
180
+		#v j:item.price="{items_sql.Цена (текущая)}"
181
+		#v j:item.disc="{items_sql.Скидка}"
182
+		#v j:item.label_color="{items_sql.Ценник}"
183
+		#v j:item.rest={items_sql.Остаток}
184
+		#v j:item.qty={items_sql.Нужно подтоварить}
185
+		#v j:item.done=[$f::if({items_sql.Выполнено},true,false)]
186
+		#v j:item.done_updated="{items_sql.Дата подтоварки}"
187
+		#v j:items[[]]=$j:item
188
+	#endfor
189
+
190
+	#v j:task.items=$j:items
191
+	#se j:result.task=$j:task
192
+
193
+#endproc
194
+#proc mshop_refill.get.update_item(task_id)
195
+	;#v user_ref=@{select ссылка from spravochniki_sotrudniki where ref=@'[j:body.access_payload.sp_ref]'@ }@
196
+
197
+#endproc
198
+
199
+#proc mshop_refill.set_done(Характеристика,done,user_ref)
200
+
201
+	#v DateTo=@{SELECT Date_format(NOW(), '%Y.%m.%d 23:59:59')}@
202
+	#v DateFrom=@{SELECT Date_format(DATE_SUB('[DateTo]', INTERVAL 1 DAY), '%Y.%m.%d 00:00:00')}@
203
+
204
+	#src nom_data
205
+	#r
206
+	SELECT
207
+	nom.Ссылка AS Номенклатура,
208
+	sznsv.Наименование AS цвет
209
+	FROM @<Справочники.ХарактеристикиНоменклатуры>@ AS xar
210
+	INNER JOIN @<Справочники.Номенклатура>@ AS nom ON nom.Ссылка=xar.Владелец
211
+	left join @<Таблицы.ЗначенияСвойств>@ znsv on znsv.Объект=xar.Ссылка and znsv.Свойство=(select ссылка from @<Справочники.НаименованияСвойств>@ where Наименование = 'цвет')
212
+	left join @<Справочники.ЗначенияСвойств>@ sznsv on sznsv.Ссылка=znsv.Значение
213
+	WHERE xar.Ссылка=[Характеристика]
214
+	#query
215
+	#endsrc
216
+
217
+	#se set_result=не изменен
218
+	#if @{select count(*) from const_podtovarka where Номенклатура={nom_data.Номенклатура} and Датаврем >= DATE_SUB(NOW(), INTERVAL 24 HOUR) and Цвет='{nom_data.цвет}'}@
219
+		#if [done]=true
220
+			@{
221
+			update const_podtovarka set Дата=date(Now()), Датаврем=Now(),Ответственный='[user_ref]' where Номенклатура={nom_data.Номенклатура}  and Дата BETWEEN '[DateFrom]' AND '[DateTo]' AND Цвет='{nom_data.цвет}'
222
+			}@
223
+			#se set_result=обновили
224
+		#else
225
+		   /*отменить подтоварку*/
226
+			@{
227
+			delete from const_podtovarka where Номенклатура={nom_data.Номенклатура} and Дата BETWEEN '[DateFrom]' AND '[DateTo]' AND Цвет='{nom_data.цвет}'
228
+			}@
229
+			#se set_result=удалили
230
+		#endif
231
+	#else
232
+		#if [done]=true
233
+			@{
234
+				insert into const_podtovarka (`Дата`, `Датаврем`,`Номенклатура`,`Характеристика`,Ответственный,Цвет)
235
+				values (date(NOW()), NOW(), {nom_data.Номенклатура}, [Характеристика], '[user_ref]', '{nom_data.цвет}')
236
+			}@
237
+			#se set_result=создали
238
+		#endif
239
+	#endif
240
+#endproc
241
+
242
+#proc mshop_refill.post.update_item
243
+
244
+	#v Характеристика=@'[j:query.item_id]'@
245
+	#v done=[j:body.done]
246
+	#v user_ref=@{select ссылка from spravochniki_sotrudniki where ref=@'[j:body.access_payload.sp_ref]'@ }@
247
+	#v j:result={{}}
248
+
249
+	#if !$Характеристика
250
+		#v j:result.result=false
251
+		#v j:result.message="Не указан item_id"
252
+		#se j:result=$j:result
253
+		#exit
254
+	#endif
255
+
256
+	#call mshop_refill.set_done($Характеристика,$done,$user_ref)
257
+
258
+	#if [set_result]=не изменен
259
+		#v j:result.result=false
260
+		#v j:result.message="товар недоступен для редактирования"
261
+		#se j:result=$j:result
262
+	#else
263
+
264
+		#v lst_upd=@{select max(podtv.ДатаВрем) from const_podtovarka as podtv where podtv.Характеристика=[Характеристика]}@
265
+		#if !$lst_upd
266
+			#v lst_upd=[$f::now()]
267
+		#endif
268
+
269
+		#v j:update_item={{}}
270
+		#v j:update_item.id=[Характеристика]
271
+		#v j:update_item.done=[done]
272
+		#v j:update_item.done_updated="[lst_upd]"
273
+
274
+		#v j:items_update=[[ ]]
275
+		#v j:items_update[[]]=$j:update_item
276
+
277
+		#v j:update={{}}
278
+		#v j:update.items=$j:items_update
279
+
280
+		#v j:result.result=true
281
+		#v j:result.message=""
282
+		#v j:result.update=$j:update
283
+
284
+		#se j:result=$j:result
285
+	#endif
286
+#endproc
287
+
288
+#proc mshop_refill.post.close_task
289
+	#v user_ref=@{select ссылка from spravochniki_sotrudniki where ref=@'[j:body.access_payload.sp_ref]'@ }@
290
+
291
+	#src items
292
+	#r
293
+
294
+	[#mshop_refill.sql_query]
295
+
296
+	#query
297
+	#endsrc
298
+
299
+	#foreach items
300
+
301
+		#if [$f::if({items.done},true,false)]=false
302
+			#call mshop_refill.set_done('{items.Характеристика}',true,$user_ref)
303
+			;TODO заполнять j:result.update как в mshop_refill.post.update_item
304
+		#endif
305
+
306
+	#endfor
307
+
308
+	#se j:result={{"result":true,"message":"Все позиции подтоварены"}}
309
+#endproc
310
+#proc mshop_refill.get.find_item
311
+	#se code=[j:query.code]
312
+
313
+	#src find_and_validate
314
+	#r
315
+	SELECT
316
+		xar.Ссылка as item_id
317
+	FROM spravochniki_xarakteristikinomenklaturi xar
318
+	INNER JOIN spravochniki_nomenklatura nom ON nom.ссылка = xar.Владелец
319
+	LEFT JOIN spravochniki_shtrixkodatovarov sht ON sht.Характеристика = xar.Ссылка
320
+	LEFT JOIN spravochniki_shtrixkoda shk ON shk.Ссылка = sht.Ссылка
321
+	INNER JOIN @<Таблицы.ОстаткиТовараВТаре>@ ost ON ost.Характеристика = xar.Ссылка
322
+	LEFT JOIN @<Справочники.Номенклатура>@ nnom ON nnom.Ссылка = nom.Родитель
323
+	LEFT JOIN @<Справочники.Номенклатура>@ nnnom ON nnnom.Ссылка = nnom.Родитель
324
+	LEFT JOIN @<Справочники.Номенклатура>@ nnnnom ON nnnnom.Ссылка = nnnom.Родитель
325
+	LEFT JOIN const_marking_values as mark on mark.Характеристика=xar.Ссылка
326
+
327
+	WHERE (
328
+		IFNULL(ШтрихКод,'null123')='[code]'
329
+		OR nom.Артикул ='[code]'
330
+		OR xar.Код='[code]'
331
+		or nom.Артикул='[code]'
332
+		OR nom.наименование like '%[code]%'
333
+		or xar.Ссылка='[code]'
334
+		OR mark.Серийныйномер='[code]'
335
+		OR mark.Кодмаркировки='[code]'
336
+	)
337
+	AND ost.Количество >= 1
338
+	AND ost.Тара = @{select ссылка from @<Справочники.Тара>@ where Наименование like 'Торговый%' limit 1}@
339
+	AND EXISTS (
340
+		SELECT 1 FROM @<Таблицы.ДвижениеТовара>@ dv
341
+		INNER JOIN @<Справочники.Тара>@ tt ON tt.Ссылка = dv.Тара
342
+		WHERE dv.Характеристика = xar.Ссылка
343
+		AND dv.Количество < 0
344
+		AND dv.Дата BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND CURDATE()
345
+		AND tt.Наименование = 'ТорговыйЗал'
346
+		LIMIT 1
347
+	)
348
+	AND nom.МинимальныйОстаток > 0
349
+	AND nnnnom.Наименование NOT IN ('СЕРТИФИКАТЫ','БИЖУТЕРИЯ','УПАКОВОЧНЫЕ ПАКЕТЫ')
350
+	LIMIT 1
351
+	#query
352
+	#endsrc
353
+	
354
+	#if !{find_and_validate}
355
+		#se j:result={{"result":false,"message":"код не опознан","item_id":""}}
356
+		#exitproc
357
+	#endif
358
+	#foreach find_and_validate
359
+		#v item_id={find_and_validate.item_id}
360
+	#endfor
361
+	#se j:result={{"result":true,"message":"","item_id":"[item_id]"}}
362
+#endproc

+ 297
- 0
modules/mshop_reprice_module.spm Целия файл

@@ -0,0 +1,297 @@
1
+#block
2
+/*
3
+{
4
+	"result": true,
5
+	"message": "",
6
+	"task": {
7
+		"id": "weeek/2026-01-01",
8
+		"title": "Переоценка м001",
9
+		"dep": "001",
10
+		"comment": "коммент",
11
+		"items": [
12
+			{
13
+				"id": "Артикул/Цвет/Документ",
14
+				"product_id": "Артикул/Цвет/Документ",
15
+				"article": "123-091",
16
+				"color": "цвет",
17
+				"size": "размер",
18
+				"sector": "сектор",
19
+				"group": "группа",
20
+				"image": "https://.../112209-0.jpg",
21
+				"title": "ТАПОЧКИ",
22
+				"base_price": 1000,
23
+				"price": 800,
24
+				"disc": "20%",
25
+				"label_color": "Белый | Красный", 
26
+				"rest": 4,
27
+				"qty": null,
28
+				"done": false,
29
+				"done_updated": "2026-01-01 12:21:11"
30
+			}
31
+		]
32
+	}
33
+}
34
+*/
35
+#endblock
36
+#proc create_tables
37
+	#src ct
38
+	#r
39
+	create table if not EXISTS [const_pereocenka_report] (
40
+		`ССЫЛКА` INT UNSIGNED NOT NULL AUTO_INCREMENT,
41
+		`ДОКУМЕНТ` INT UNSIGNED NOT NULL,
42
+		`АРТИКУЛ` VARCHAR(50) NOT NULL,
43
+		`ЦВЕТ` VARCHAR(50) NOT NULL,
44
+		`ЦЕНА` INT NOT NULL,
45
+		`ДатаИзменения` datetime default NULL,
46
+		PRIMARY KEY (`ССЫЛКА`),
47
+		KEY (`ДОКУМЕНТ`),
48
+		KEY (`АРТИКУЛ`),
49
+		KEY (`ЦВЕТ`),
50
+		KEY (`ЦЕНА`),
51
+		KEY (`ДатаИзменения`),
52
+		UNIQUE KEY (`ДОКУМЕНТ`,`АРТИКУЛ`,`ЦВЕТ`,`ЦЕНА`)                                  
53
+	)  ENGINE=InnoDB  CHARACTER SET cp1251;
54
+	#query
55
+	#endsrc
56
+	
57
+	#if !@{select 1 from information_schema.columns where table_schema=schema() and table_name='const_pereocenka_report' and column_name='ДатаИзменения'}@
58
+		@{alter table [const_pereocenka_report] add ДатаИзменения datetime default NULL;}@
59
+	#endif
60
+#endproc
61
+#proc init_params
62
+	#include_module price_module
63
+	#se const_pereocenka_report=const_pereocenka_report
64
+	#globalobjs_get Dep.Код
65
+	#se Подразделение.код=[dep.код]
66
+	
67
+	#se DateTo=@{SELECT Date_format(NOW(), '%Y.%m.%d 23:59:59')}@
68
+	#if [task_id]=week
69
+		#se DateFrom=@{SELECT Date_format(DATE_SUB('[DateTo]', INTERVAL 7 DAY), '%Y.%m.%d 00:00:00')}@
70
+	#else
71
+		#if [task_id]=daily
72
+			#se DateFrom=@{SELECT Date_format(DATE_SUB('[DateTo]', INTERVAL 1 DAY), '%Y.%m.%d 00:00:00')}@
73
+		#else
74
+			#se DateFrom=@{SELECT Date_format('[task_id]', '%Y.%m.%d 00:00:00')}@
75
+		#endif
76
+	#endif
77
+
78
+	;#se DF=@{select Date_format(DATE_ADD('[DateFrom]', INTERVAL -1 DAY), '%Y.%m.%d 16:00:00')}@
79
+	;#se DT=@{select Date_format('[DateTo]', '%Y.%m.%d 23:59:59')}@
80
+
81
+	;#se user_ref=[user_ref]
82
+	#se user_ref=@{select ссылка from spravochniki_sotrudniki where ref=@'[j:body.access_payload.sp_ref]'@ }@
83
+	#se store_id=@{select MAX(ссылка) from spravochniki_tara where наименование like '%торговый%зал%'}@
84
+	#se tara_t=[store_id]
85
+	#se PlanPriceType=@{select Ссылка from spravochniki_tipicen as tp  where Наименование='РозницаПлан'}@
86
+
87
+
88
+#endproc
89
+#proc mshop_reprice.sql_query
90
+
91
+	#call init_params
92
+	#call create_tables
93
+	#se report_ref=@{SELECT UUID_SHORT();}@
94
+	#se SELECT_QUERY=@!,concat('https://media.saticogroup.com/dm/goodpics/marmalato?good_id=',if(c_name.Наименование is null,substring_index((select min(Код) from @<Справочники.ХарактеристикиНоменклатуры>@ as xar where xar.Владелец=nom.Ссылка),',',1),substring_index(xar.Код,',',1))) as Фото_link ,s_name.Наименование AS 'Размер'!@
95
+	#include_module reprice_sql
96
+	[#reprice_sql.build_query]
97
+
98
+#endproc
99
+#proc mshop_reprice.get.list
100
+	/*не актуальный*/
101
+	#src stats
102
+	#r
103
+		select count(distinct IF(IFNULL(LENGTH(`Подтоварить`),0)>0 AND `Дата подтоварки`>date(date_sub(now(),interval 6 hour)),Характеристика,NULL))   as items_done,
104
+				count(distinct IF(IFNULL(LENGTH(`Подтоварить`),0)=0 OR `Дата подтоварки`>date(date_sub(now(),interval 6 hour)),Характеристика,NULL))   as items
105
+		from ([#mshop_reprice.sql_query]) as qq
106
+	#query
107
+	#endsrc
108
+
109
+	#se j:result={{"result":true,"message":""}}
110
+
111
+	#v j:task={{}}
112
+	#v j:task.id="torg_zal"
113
+	#v j:task.title="ПОДТОВАРКА ТЗ"
114
+	#v j:task.created="[$f::now]"
115
+	#v j:task.comment="Подтоварка торгового зала"
116
+
117
+	#if {stats}
118
+		#v j:task.items_count={stats.items}
119
+		#v j:task.items_done={stats.items_done}
120
+	#else
121
+		#v j:task.items_count=0
122
+		#v j:task.items_done=0
123
+	#endif
124
+
125
+	#se j:result.tasks=[[ [j:task] ]]
126
+
127
+#endproc
128
+
129
+#proc mshop_reprice.get.task
130
+
131
+	#se task_id=[j:query.task_id]
132
+
133
+	#src items_sql
134
+	#r
135
+		[#mshop_reprice.sql_query]
136
+	#query
137
+	#endsrc
138
+
139
+	#se j:result={{"result":true,"message":""}}
140
+
141
+	#v DF=@{select Date_format('[DateFrom]', '%d.%m.%Y')}@
142
+	#v DT=@{select Date_format('[DateTo]', '%d.%m.%Y')}@
143
+
144
+	#v j:task={{}}
145
+	#v j:task.id="[task_id]"
146
+	#v j:task.title="Переоценка м[Подразделение.код]"
147
+	#v j:task.dep="[Подразделение.код]"
148
+	#v j:task.comment="За период с [DF] по [DT]"
149
+
150
+	#v j:items=[[ ]]
151
+	#foreach items_sql
152
+		#v j:item={{}}
153
+
154
+		#v j:item.id="{items_sql.pos_id}"
155
+		#v j:item.product_id="{items_sql.Коды}"
156
+		#v j:item.article="{items_sql.Артикул}"
157
+		#v j:item.color="{items_sql.Цвет}"
158
+		#v j:item.size="{items_sql.Размер}"
159
+		#v j:item.sector="{items_sql.Сектор}"
160
+		#v j:item.group="{items_sql.Группа}"
161
+		#v j:item.image="{items_sql.Фото_link}"
162
+		#v j:item.title="{items_sql.Наименование}"
163
+		#v j:item.base_price="{items_sql.Цена план}"
164
+		#v j:item.price="{items_sql.Цена новая}"
165
+		#v j:item.disc="{items_sql.Скидка, %}"
166
+		#v j:item.label_color="{items_sql.Ценник}"
167
+		#v j:item.rest={items_sql.Остаток (арт.+цвет)}
168
+		#v j:item.qty={items_sql.Остаток (арт.+цвет)}
169
+		#v j:item.done=[$f::if({items_sql.done},true,false)]
170
+		#v j:item.done_updated="{items_sql.done_updated}"
171
+		#v j:items[[]]=$j:item
172
+	#endfor
173
+
174
+	#v j:task.items=$j:items
175
+	#se j:result.task=$j:task
176
+
177
+#endproc
178
+
179
+#proc mshop_reprice.post.update_item
180
+
181
+	#se const_pereocenka_report=const_pereocenka_report
182
+	#v tov_id=[j:query.item_id]
183
+	#v done=[j:body.done]
184
+	#v user_ref=@{select ссылка from spravochniki_sotrudniki where ref=@'[j:body.access_payload.sp_ref]'@ }@
185
+	#v j:result={{}}
186
+
187
+	#if !$tov_id
188
+		#v j:result.result=false
189
+		#v j:result.message="Не указан код товара"
190
+		#se j:result=$j:result
191
+		#exit
192
+	#endif
193
+	#v (artikul,color,doc,price)=@{SELECT CONCAT_WS(',', SUBSTRING_INDEX('[tov_id]', '/', 1), SUBSTRING_INDEX(SUBSTRING_INDEX('[tov_id]', '/', 2), '/', -1), SUBSTRING_INDEX(SUBSTRING_INDEX('[tov_id]', '/', 3), '/', -1), SUBSTRING_INDEX('[tov_id]', '/', -1))}@
194
+
195
+
196
+	;#v tov_exist=@{SELECT 1 FROM INNER JOIN WHERE = AND }@
197
+	;TODO проверка существования товара по артикул + цвет
198
+	#v lst_upd=[$f::now()]
199
+	#if [done]=true
200
+		@{INSERT INTO [const_pereocenka_report] (ДОКУМЕНТ, АРТИКУЛ, ЦВЕТ, ЦЕНА, ДатаИзменения) VALUES('[doc]','[artikul]','[color]','[price]', NOW()) ON DUPLICATE KEY UPDATE ДатаИзменения = VALUES(ДатаИзменения)}@
201
+	#else
202
+		#se nl=@{DELETE FROM [const_pereocenka_report] WHERE ДОКУМЕНТ='[doc]' AND АРТИКУЛ='[artikul]' AND ЦВЕТ='[color]' AND ЦЕНА='[price]'}@
203
+	#endif
204
+
205
+	#v j:update_item={{}}
206
+	#v j:update_item.id="[tov_id]"
207
+	#v j:update_item.done=[done]
208
+	#v j:update_item.done_updated="[lst_upd]"
209
+
210
+	#v j:items_update=[[ ]]
211
+	#v j:items_update[[]]=$j:update_item
212
+
213
+	#v j:update={{}}
214
+	#v j:update.items=$j:items_update
215
+
216
+	#v j:result.result=true
217
+	#v j:result.message=""
218
+	#v j:result.update=$j:update
219
+
220
+	#se j:result=$j:result
221
+#endproc
222
+#proc mshop_reprice.post.close_task
223
+	/*TODO переписать для reprice*/
224
+	#exit
225
+	#v user_ref=@{select ссылка from spravochniki_sotrudniki where ref=@'[j:body.access_payload.sp_ref]'@ }@
226
+
227
+	#src items_sql
228
+	#r
229
+	[#mshop_reprice.sql_query]
230
+	#query
231
+	#endsrc
232
+
233
+	#foreach items_sql
234
+
235
+		#if [$f::if({items_sql.done},true,false)]=false
236
+			#call mshop_refill.set_done('{items_sql.Характеристика}',true,$user_ref)
237
+			;TODO заполнять j:result.update как в mshop_refill.post.update_item
238
+		#endif
239
+
240
+	#endfor
241
+
242
+	#se j:result={{"result":true,"message":"Все позиции подтоварены"}}
243
+#endproc
244
+#proc mshop_reprice.get.find_item
245
+	#se code=[j:query.code]
246
+	#globalobjs_get Dep.Код
247
+	#src price_col
248
+	#r
249
+	Select tc.ссылка as 'Тип_цены_ссылка', IFNULL(tc.БАЗОВЫЙТИПЦЕН, 0) as 'Тип_цены_базовый_ссылка'
250
+	From @<Справочники.Подразделения>@ as podr inner join @<Справочники.ТипыЦен>@ as tc on tc.ссылка = podr.ТИПЦЕН
251
+	Where podr.КОД='[Dep.Код]'
252
+	#query
253
+	#endsrc
254
+
255
+	#src find_sql
256
+	#r
257
+	SELECT
258
+		CONCAT(nom.АРТИКУЛ, '/', IFNULL(c_name.Наименование, '*'), '/', pr.ДОКУМЕНТ, '/', ROUND(pr.ЦЕНА)) AS 'pos_id'
259
+	FROM @<Таблицы.Прайсы>@ as pr
260
+	INNER JOIN @<Документы.УстановкаЦенНоменклатуры>@ as uc ON uc.ССЫЛКА = pr.ДОКУМЕНТ
261
+	INNER JOIN @<Справочники.Номенклатура>@ as nom ON nom.ссылка = pr.НОМЕНКЛАТУРА
262
+	LEFT JOIN @<Справочники.ХарактеристикиНоменклатуры>@ as xar ON xar.ссылка = pr.ХАРАКТЕРИСТИКА
263
+
264
+	LEFT JOIN @<таблицы.значениясвойств>@ as ssv_c ON ssv_c.объект = pr.ХАРАКТЕРИСТИКА AND ssv_c.свойство = (Select MAX(ссылка) From @<Справочники.НаименованияСвойств>@ Where наименование = 'Цвет')
265
+	LEFT JOIN @<Справочники.ЗначенияСвойств>@ as c_name ON c_name.Ссылка = ssv_c.Значение
266
+
267
+	LEFT JOIN @<Таблицы.ОстаткиТовараВТаре>@ as dv ON dv.ХАРАКТЕРИСТИКА = pr.ХАРАКТЕРИСТИКА AND dv.КАЧЕСТВО = 'НОВЫЙ' AND dv.ТАРА = [tara_t]
268
+	LEFT JOIN @<Справочники.ШтрихКодаТоваров>@ as sht ON sht.Характеристика = xar.ссылка
269
+	LEFT JOIN @<Справочники.ШтрихКода>@ as sh ON sh.Ссылка = sht.Ссылка
270
+	LEFT JOIN const_marking_values as mark on mark.Характеристика=xar.Ссылка
271
+
272
+	WHERE pr.ТИПЦЕНЫ IN ({price_col.Тип_цены_ссылка}, {price_col.Тип_цены_базовый_ссылка})
273
+	AND pr.КАЧЕСТВО = 'НОВЫЙ'
274
+	AND (
275
+		nom.АРТИКУЛ ='[code]'
276
+		OR xar.КОД ='[code]'
277
+		OR nom.НАИМЕНОВАНИЕ LIKE '%[code]%'
278
+		OR xar.ссылка ='[code]'
279
+		OR sh.ШтрихКод ='[code]'
280
+		OR mark.Серийныйномер='[code]'
281
+		OR mark.Кодмаркировки='[code]'
282
+	)
283
+	GROUP BY pr.НОМЕНКЛАТУРА, IFNULL(c_name.Наименование, '*'), ROUND(pr.ЦЕНА)
284
+	HAVING IFNULL(SUM(dv.КОЛИЧЕСТВО), 0) > 0
285
+	LIMIT 1
286
+	#query
287
+	#endsrc
288
+	
289
+	#if {find_sql.pos_id}
290
+		#se j:result={{"result":true,"message":"Найден","item_id":"{find_sql.pos_id}"}}
291
+	#else
292
+		;#if {find_sql.}
293
+		;	#se j:result={{"result":false,"message":"Код не опознан","item_id":""}}
294
+		;#else
295
+			#se j:result={{"result":false,"message":"Товар не входит в текущее задание","item_id":""}}
296
+	#endif
297
+#endproc

+ 239
- 0
modules/mshop_service_module.spm Целия файл

@@ -0,0 +1,239 @@
1
+#proc get_printer_name
2
+
3
+#env_params_get ПРИНТЕРЭТИКЕТОК.WSPOOLER.PRINTERNAME
4
+/*ZDesigner ZD410-203dpi ZPL стандартное название принтера зебра*/
5
+#v name=[ПРИНТЕРЭТИКЕТОК.WSPOOLER.PRINTERNAME]
6
+
7
+#win_enumprinters printer_list
8
+#v printer
9
+#for v=([printer_list])\;
10
+	#continue ? ![v#?ZDesigner] && ![v#?TSC]
11
+	#v printer=[v]
12
+	#break ? !$name
13
+	#break ? $v=$name
14
+#endfor
15
+[printer]
16
+#endproc
17
+
18
+#proc mshop_service.execute_print_engine(Характеристика, Количество, Шаблон)
19
+#r
20
+#v template_text=@{select Шаблон from @<Справочники.ШаблоныПечатиЭтикеток>@ where Наименование='[Шаблон]' }@
21
+#case !$template_text #then #exception Шаблон '[Шаблон]' не найден!
22
+#globalobjs_get Dep.ссылка
23
+#out_save proc_out
24
+
25
+#try
26
+#o sticker
27
+#se Характеристика.ссылка=[Характеристика]
28
+#se Подразделение.ссылка=[Dep.ссылка]
29
+#se КОЛ-ВО КОПИЙ=[Количество]
30
+#se КОЛИЧЕСТВО=[Количество]
31
+
32
+#macro_load_from_var macro_stemplate=template_text
33
+#macro_exec macro_stemplate
34
+
35
+#v printer=[#get_printer_name]
36
+
37
+#if !$printer
38
+	#exception В системе не настроен принтер этикеток, обратитесь в тех поддержку;
39
+#endif
40
+
41
+#win_rawprint [printer],sticker,test_sticker
42
+
43
+#catch
44
+	#win_enumprinters printer_list
45
+	;#se error=[?%exception.short_msg];[?%exception.msg];ENV [$env];Выбран: [?name] Список: [?printer_list]
46
+	#se error=[?%exception.msg] [$endl]Список доступных принтеров: [?printer_list];[$endl]Выбранный принтер: [?printer].
47
+	#se j:result={{"result":false,"message":"[error]"}}
48
+	#exitproc
49
+#endtry
50
+#r
51
+#out_restore proc_out
52
+#env_get_env
53
+#se j:result={{"result":true,"message":"Ценник отправлен на принтер:'[?printer]', среда:'[env_get_env]'"}}
54
+#endproc
55
+#proc mshop_service.execute_print_engine_2(Характеристика, Количество, Шаблон)
56
+
57
+	#v template_text=@{select Шаблон from @<Справочники.ШаблоныПечатиЭтикеток>@ where Наименование='[Шаблон]' }@
58
+	#case !$template_text #then #exception Шаблон '[Шаблон]' не найден!
59
+	#globalobjs_get Dep.ссылка
60
+	#out_save proc_out
61
+
62
+	#try
63
+		#o sticker
64
+		#r
65
+		#se Характеристика.ссылка=[Характеристика]
66
+		#se Подразделение.ссылка=[Dep.ссылка]
67
+		#se КОЛ-ВО КОПИЙ=[Количество]
68
+		#se КОЛИЧЕСТВО=[Количество]
69
+
70
+		#macro_load_from_var macro_stemplate=template_text
71
+		#macro_exec macro_stemplate
72
+
73
+		#splp_connect
74
+		#splp_send_out
75
+
76
+	#catch
77
+		#se error=[?%exception.short_msg];[?%exception.msg];ENV [$env];
78
+		#se j:result={{"result":false,"message":"[error]"}}
79
+		#exitproc
80
+	#endtry
81
+
82
+	#r
83
+	#out_restore proc_out
84
+	#env_get_env
85
+	#se j:result={{"result":true,"message":"Запрос на печать успешно обработан.  среда:'[env_get_env]'"}}
86
+#endproc
87
+
88
+#proc mshop_service.post.print_label
89
+#v Количество=[j:query.count]
90
+#v Шаблон=ЦенникНаТоварНовый/*поддержать выбор размера ценника результат выполнения get label_templates*/
91
+;#v Шаблон=@'[j:query.template]'@
92
+#se j:result={{"result":true,"message":""}}
93
+
94
+#if ![j:query.product_id]
95
+	#se j:result={{"result":false,"message":"не переданы коды товаров для печати"}}
96
+	#exit
97
+#endif
98
+
99
+#for tov=([j:query.product_id])
100
+	#v xar=@{SELECT xar.Ссылка as tov_id FROM @<Справочники.ХарактеристикиНоменклатуры>@ as xar WHERE xar.Код='[tov]'}@
101
+	#if !$xar
102
+		#se j:result={{"result":false,"message":"Товар [tov] не найден"}}
103
+		#exitproc
104
+	#endif
105
+	#call mshop_service.execute_print_engine([xar],[Количество],[Шаблон])
106
+#endfor
107
+#endproc
108
+#proc mshop_service.get.print_label
109
+#v Количество=[j:query.count]
110
+#v Шаблон=ЦенникНаТоварНовый/*поддержать выбор размера ценника результат выполнения get label_templates*/
111
+;#v Шаблон=@'[j:query.template]'@
112
+#se j:result={{"result":true,"message":""}}
113
+
114
+#if ![j:query.product_id]
115
+	#se j:result={{"result":false,"message":"не переданы коды товаров для печати"}}
116
+	#exitproc
117
+#endif
118
+
119
+#for tov=([j:query.product_id])
120
+	#v xar=@{SELECT xar.Ссылка as tov_id FROM @<Справочники.ХарактеристикиНоменклатуры>@ as xar WHERE xar.Код='[tov]'}@
121
+	#if !$xar
122
+		#se j:result={{"result":false,"message":"Товар [tov] не найден"}}
123
+		#exitproc
124
+	#endif
125
+	#call mshop_service.execute_print_engine([xar],[Количество],[Шаблон])
126
+#endfor
127
+#endproc
128
+#proc mshop_service.get.label_templates
129
+	#se j:result={{"result":true,"message":"","templates":[[]]}}
130
+#endproc
131
+#proc mshop_service.get.product_info
132
+	#include_module price_module
133
+	#se form_date=[$f::now()]
134
+	#globalobjs_get Dep.Код
135
+	#se Подразделение.код=[dep.код]
136
+	#se PriceType=@{select tp.ссылка from spravochniki_tipicen as tp inner join spravochniki_podrazdeleniya as dep on dep.ТипЦен=tp.ссылка where dep.Код='[Подразделение.Код]'}@
137
+	#se BasePriceType=@{select IFNULL(БазовыйТипЦен,0) from spravochniki_tipicen as tp inner join spravochniki_podrazdeleniya as dep on dep.ТипЦен=tp.ссылка where dep.Код='[Подразделение.Код]'}@
138
+	#se PlanPriceType=@{select Ссылка from spravochniki_tipicen as tp  where Наименование='РозницаПлан'}@
139
+
140
+	#v product_code=[j:query.product_id] /*Код/Серия/Штрихкод/Маркировка*/
141
+
142
+	#se j:result={{"result":true,"message":""}}
143
+	#src tov_data
144
+	#r
145
+	SELECT
146
+		xar.Код AS Код,
147
+		nom.Артикул AS Артикул,
148
+		nom.Наименование AS наименование,
149
+		sznsv_color.Наименование AS цвет,
150
+		sznsv_size.Наименование AS Размер,
151
+		coalesce(ROUND(pr_xxar.Цена), ROUND(pr_nom.Цена), ROUND(pr_base_xxar.Цена), ROUND(pr_base_nom.Цена), 0) as Цена,
152
+		coalesce(ROUND(pr_plan_xxar.Цена), ROUND(pr_plan_nom.Цена), 0) as Цена_план,
153
+		concat(if(coalesce(pr_plan_xxar.Цена, pr_plan_nom.Цена) > coalesce(pr_xxar.Цена, pr_nom.Цена, pr_base_xxar.Цена, pr_base_nom.Цена), -1, 1) * ROUND((( coalesce(pr_plan_xxar.Цена, pr_plan_nom.Цена) - coalesce(pr_xxar.Цена, pr_nom.Цена, pr_base_xxar.Цена, pr_base_nom.Цена) ) / coalesce(pr_plan_xxar.Цена, pr_plan_nom.Цена) ) * 100), '%') as Скидка,
154
+		[#price.doc_label_type_sql(uc)] as Цвет_ценника
155
+	FROM @<Справочники.ХарактеристикиНоменклатуры>@ AS xar
156
+	INNER JOIN @<Справочники.Номенклатура>@ AS nom ON nom.Ссылка=xar.Владелец
157
+	left join @<Таблицы.ЗначенияСвойств>@ znsv_color on znsv_color.Объект=xar.Ссылка and znsv_color.Свойство=(select ссылка from @<Справочники.НаименованияСвойств>@ where Наименование = 'цвет')
158
+	left join @<Справочники.ЗначенияСвойств>@ sznsv_color on sznsv_color.Ссылка=znsv_color.Значение
159
+	left join @<Таблицы.ЗначенияСвойств>@ znsv_size on znsv_size.Объект=xar.Ссылка and znsv_size.Свойство=(select ссылка from @<Справочники.НаименованияСвойств>@ where Наименование = 'размер')
160
+	left join @<Справочники.ЗначенияСвойств>@ sznsv_size on sznsv_size.Ссылка=znsv_size.Значение
161
+
162
+	left join tablici_prajsi as pr_base_nom on pr_base_nom.Номенклатура=nom.ссылка and pr_base_nom.ТипЦены='[BasePriceType]' and pr_base_nom.Характеристика=0 AND pr_base_nom.Дата <= '[form_date]'
163
+	left join tablici_prajsi as pr_base_xxar on pr_base_xxar.Номенклатура=nom.ссылка and pr_base_xxar.ТипЦены='[BasePriceType]' and pr_base_xxar.Характеристика=xar.ссылка AND pr_base_xxar.Дата <= '[form_date]' and pr_base_xxar.Дата>=IFNULL(pr_base_nom.Дата,pr_base_xxar.Дата)
164
+
165
+	left join tablici_prajsi as pr_nom on pr_nom.Номенклатура=nom.ссылка and pr_nom.ТипЦены='[PriceType]' and pr_nom.Характеристика=0 AND pr_nom.Дата <= '[form_date]' and pr_nom.Дата>=GREATEST(IFNULL(pr_base_nom.Дата, pr_nom.Дата),IFNULL(pr_base_xxar.Дата, pr_nom.Дата) )
166
+	left join tablici_prajsi as pr_xxar on pr_xxar.Номенклатура=nom.ссылка and pr_xxar.ТипЦены='[PriceType]' and pr_xxar.Характеристика=xar.ссылка AND pr_xxar.Дата <= '[form_date]' and pr_xxar.Дата>=GREATEST(IFNULL(pr_base_nom.Дата, pr_xxar.Дата),IFNULL(pr_base_xxar.Дата, pr_xxar.Дата),IFNULL(pr_nom.Дата, pr_xxar.Дата) )
167
+
168
+	left join tablici_prajsi as pr_plan_nom on pr_plan_nom.Номенклатура=nom.ссылка and pr_plan_nom.ТипЦены='[PlanPriceType]' and pr_plan_nom.Характеристика=0 AND pr_plan_nom.Дата <= '[form_date]'
169
+	left join tablici_prajsi as pr_plan_xxar on pr_plan_xxar.Номенклатура=nom.ссылка and pr_plan_xxar.ТипЦены='[PlanPriceType]' and pr_plan_xxar.Характеристика=xar.ссылка AND pr_plan_xxar.Дата <= '[form_date]' and pr_plan_xxar.Дата>=IFNULL(pr_plan_nom.Дата,pr_plan_xxar.Дата)
170
+
171
+	left join @<Документы.УстановкаЦенНоменклатуры>@ as uc on uc.ССЫЛКА = coalesce(pr_xxar.Документ, pr_nom.Документ, pr_base_xxar.Документ, pr_base_nom.Документ)
172
+	WHERE xar.Код='[product_code]'
173
+	#query
174
+	#endsrc
175
+
176
+	#if !{tov_data}
177
+		#se j:result={{"result":false,"message":"Товар с кодом '[product_code]' не найден"}}
178
+		#exitproc
179
+	#endif
180
+	#v j:product_info={{}}
181
+	#v j:product_info.code='{tov_data.Код}'
182
+	#v j:product_info.article='{tov_data.Артикул}'
183
+	#v j:product_info.title='{tov_data.наименование}'
184
+	#v j:product_info.color='{tov_data.цвет}'
185
+	#v j:product_info.size='{tov_data.Размер}'
186
+	#v j:product_info.price={tov_data.Цена}
187
+	#v j:product_info.price_full={tov_data.Цена_план}
188
+	#v j:product_info.discount_title='{tov_data.Скидка}'
189
+	#v j:product_info.label_color="{tov_data.Цвет_ценника}"
190
+	
191
+	#src tov_sizes
192
+	#r
193
+	SELECT 
194
+		t.size,
195
+		MAX(t.code) as code,
196
+		GROUP_CONCAT(DISTINCT CONCAT(t.code, ':', t.qty) ORDER BY t.code SEPARATOR ',') all_codes,
197
+		SUM(t.qty) as quantity
198
+	FROM (
199
+		SELECT 
200
+			sznsv.Наименование as size,
201
+			xar.Код as code,
202
+			SUM(ost.КОЛИЧЕСТВО) as qty
203
+		FROM @<Справочники.Номенклатура>@ AS nom
204
+		INNER JOIN @<Справочники.ХарактеристикиНоменклатуры>@ as xar ON xar.Владелец=nom.Ссылка
205
+
206
+		INNER JOIN @<Таблицы.ЗначенияСвойств>@ znsv2 on znsv2.Объект=xar.Ссылка and znsv2.Свойство=(select ссылка from @<Справочники.НаименованияСвойств>@ where Наименование='Цвет')
207
+		INNER join @<Справочники.ЗначенияСвойств>@ sznsv2 on sznsv2.Ссылка=znsv2.Значение
208
+
209
+		INNER JOIN @<Таблицы.ЗначенияСвойств>@ znsv on znsv.Объект=xar.Ссылка and znsv.Свойство=(select ссылка from @<Справочники.НаименованияСвойств>@ where Наименование='размер')
210
+		INNER join @<Справочники.ЗначенияСвойств>@ sznsv on sznsv.Ссылка=znsv.Значение
211
+
212
+		INNER JOIN @<Таблицы.ОстаткиТовараВТаре>@ ost 
213
+			ON ost.ХАРАКТЕРИСТИКА = xar.Ссылка 
214
+			AND ost.ТАРА = @{SELECT ССЫЛКА FROM @<Справочники.Тара>@ WHERE Наименование='ТорговыйЗал'}@
215
+
216
+		WHERE 
217
+			nom.Артикул='{tov_data.Артикул}' 
218
+			AND sznsv2.Наименование='{tov_data.цвет}'
219
+		GROUP BY xar.Ссылка, sznsv.Наименование, xar.Код
220
+		HAVING SUM(ost.КОЛИЧЕСТВО) > 0
221
+	) t
222
+	GROUP BY t.size
223
+	ORDER BY t.size
224
+	#query
225
+	#endsrc
226
+	
227
+	#v j:all_sizes=[[]]
228
+	#foreach tov_sizes
229
+		#v j:all_size={{}}
230
+		#v j:all_size.size='{tov_sizes.size}'
231
+		#v j:all_size.code='{tov_sizes.code}'
232
+		#v j:all_size.all_codes='{tov_sizes.all_codes}'
233
+		#v j:all_sizes[[]]=$j:all_size
234
+	#endfor
235
+	
236
+	#v j:product_info.all_sizes=$j:all_sizes
237
+	#se j:result.product_info=$j:product_info
238
+	
239
+#endproc

+ 153
- 0
modules/reprice_sql.spm Целия файл

@@ -0,0 +1,153 @@
1
+/*параметры #se : Подразделение.код, report_ref, tara_t, old_price, DateFrom, DateTo, PlanPriceType, const_pereocenka_report, SELECT_QUERY */
2
+
3
+#proc reprice_sql.build_query
4
+#include_module price_module
5
+#src price_col
6
+#src_reset
7
+Select
8
+	tc.ссылка as 'Тип_цены_ссылка'
9
+	,IFNULL(tc.БАЗОВЫЙТИПЦЕН, 0) as 'Тип_цены_базовый_ссылка'
10
+From @<Справочники.Подразделения>@ as podr
11
+inner join @<Справочники.ТипыЦен>@ as tc on tc.ссылка = podr.ТИПЦЕН
12
+Where podr.КОД = '[Подразделение.код]';
13
+#query
14
+#endsrc
15
+
16
+#src ost
17
+#src_reset
18
+drop temporary table if exists ost[report_ref];
19
+create temporary table ost[report_ref] ENGINE=MyISAM
20
+Select
21
+	dv.НОМЕНКЛАТУРА as 'НОМЕНКЛАТУРА'
22
+	,CONCAT('*,', GROUP_CONCAT(DISTINCT IFNULL(c_name.Наименование, ''))) as 'ЦВЕТА'
23
+	,SUM(dv.КОЛИЧЕСТВО) as `КОЛИЧЕСТВО`
24
+From @<Таблицы.ОстаткиТовараВТаре>@ as dv
25
+left join @<таблицы.значениясвойств>@ as ssv_с on ssv_с.объект = dv.ХАРАКТЕРИСТИКА and ssv_с.свойство = (Select MAX(ссылка) From @<Справочники.НаименованияСвойств>@ Where наименование = 'Цвет')
26
+left join @<Справочники.ЗначенияСвойств>@ as c_name on c_name.Ссылка = ssv_с.Значение
27
+Where dv.ТАРА = [tara_t]
28
+AND dv.КАЧЕСТВО = 'НОВЫЙ'
29
+Group by
30
+	dv.НОМЕНКЛАТУРА
31
+Having
32
+	`КОЛИЧЕСТВО`
33
+Order by
34
+	NULL;
35
+#query
36
+#endsrc
37
+
38
+#set nl=@{alter table ost[report_ref] add index(НОМЕНКЛАТУРА)}@
39
+#set nl=@{SET @N:=0}@
40
+
41
+#src report
42
+#src_reset
43
+drop temporary table if exists report[report_ref];
44
+create temporary table report[report_ref] ENGINE=MyISAM
45
+Select
46
+	@N:=@N+1 as 'Ссылка'
47
+	,nom.Ссылка Номенклатура
48
+	,pr.ДАТА as 'Дата_цены'
49
+	,nnnnom.Наименование as 'Сектор'
50
+	,IFNULL(nnnom.НАИМЕНОВАНИЕ, 'НЕЗАДАНА') as 'Группа'
51
+	,nom.НАИМЕНОВАНИЕ as 'Наименование'
52
+	,nom.АРТИКУЛ as 'Артикул'
53
+	,if(c_name.Наименование is null,substring_index((select min(Код) from @<Справочники.ХарактеристикиНоменклатуры>@ as xar where xar.Владелец=nom.Ссылка),',',1),substring_index(xar.Код,',',1)) as Фото
54
+	,IFNULL(c_name.Наименование, '*') as 'Цвет'
55
+	,GROUP_CONCAT(DISTINCT xar.КОД SEPARATOR ',') as 'Коды'
56
+
57
+#if $old_price
58
+	(Select ROUND(ic.ЦЕНА) From @<Таблицы.ИзменениеЦены>@ as ic FORCE KEY(НОМЕНКЛАТУРА) Where ic.ДАТА < '[DateFrom]' AND ic.ТИПЦЕНЫ = {price_col.Тип_цены_базовый_ссылка} AND ic.НОМЕНКЛАТУРА = pr.НОМЕНКЛАТУРА AND ic.ХАРАКТЕРИСТИКА = 0 AND ic.КАЧЕСТВО = pr.КАЧЕСТВО Order by ic.ДАТА DESC LIMIT 1)))) as 'Цена_старая'
59
+#else
60
+	,'' as 'Цена_старая'
61
+#endif
62
+	/* там выше ранее был рабочий(?) алгоритм зачем его закоментили и написали неправильную формулу ? если новая переоценка на хар=0 то старая цена берется только тоже из строк где хар=0 */
63
+; , (Select ROUND(ic.ЦЕНА) From @<Таблицы.ИзменениеЦены>@ as ic FORCE KEY(НОМЕНКЛАТУРА) Where ic.ДАТА < '[DateFrom]' AND ic.НОМЕНКЛАТУРА = pr.НОМЕНКЛАТУРА AND (ic.ТИПЦЕНЫ = {price_col.Тип_цены_базовый_ссылка} OR  ic.ТИПЦЕНЫ = pr.ТИПЦЕНЫ) AND (ic.ХАРАКТЕРИСТИКА = 0 OR  ic.ХАРАКТЕРИСТИКА = pr.ХАРАКТЕРИСТИКА ) AND ic.КАЧЕСТВО = pr.КАЧЕСТВО Order by ic.ДАТА DESC LIMIT 1) as 'Цена_старая'
64
+;  ,(Select ROUND(ic.ЦЕНА) From @<Таблицы.ИзменениеЦены>@ as ic FORCE KEY(НОМЕНКЛАТУРА) Where ic.ДАТА < '[DateFrom]' AND ic.НОМЕНКЛАТУРА = pr.НОМЕНКЛАТУРА AND (ic.ТИПЦЕНЫ = {price_col.Тип_цены_базовый_ссылка} OR  ic.ТИПЦЕНЫ = pr.ТИПЦЕНЫ) AND IF(pr.ХАРАКТЕРИСТИКА = 0, 1, (ic.ХАРАКТЕРИСТИКА = 0 OR  ic.ХАРАКТЕРИСТИКА = pr.ХАРАКТЕРИСТИКА)) AND ic.КАЧЕСТВО = pr.КАЧЕСТВО Order by ic.ДАТА DESC LIMIT 1) as 'Цена_старая'
65
+	,[#price.doc_label_type_sql(uc)] as 'Ценник'
66
+	,ROUND(pr.ЦЕНА) as 'Цена_новая'
67
+	,coalesce(ROUND(pr_plan_xxar.Цена), ROUND(pr_plan_nom.Цена), 'нет') as 'Цена_план'
68
+	,IF(INSTR(IFNULL(ost.ЦВЕТА, ''), IFNULL(c_name.Наименование, '*')), IFNULL(ost.КОЛИЧЕСТВО,0), 0) as 'Остаток_арт'
69
+	,IFNULL(SUM(dv.КОЛИЧЕСТВО), 0) as 'Остаток_арт_цвет'
70
+	,MAX(pr.ДОКУМЕНТ) as 'ДОКУМЕНТ'
71
+	[SELECT_QUERY]
72
+
73
+From @<Таблицы.Прайсы>@ as pr
74
+inner join @<Документы.УстановкаЦенНоменклатуры>@ as uc on uc.ССЫЛКА = pr.ДОКУМЕНТ
75
+inner join @<Справочники.Номенклатура>@ as nom on nom.ссылка = pr.НОМЕНКЛАТУРА
76
+left join @<Справочники.Номенклатура>@ as nnom on nnom.Ссылка = nom.Родитель
77
+left join @<Справочники.Номенклатура>@ as nnnom on nnnom.Ссылка = nnom.Родитель
78
+left join @<Справочники.Номенклатура>@ as nnnnom on nnnnom.Ссылка = nnnom.Родитель
79
+inner join @<Справочники.ХарактеристикиНоменклатуры>@ as xar 
80
+	on xar.Владелец=nom.Ссылка 
81
+	and xar.ссылка = if(IFNULL(pr.ХАРАКТЕРИСТИКА,0) = 0, xar.Ссылка, pr.ХАРАКТЕРИСТИКА)
82
+left join @<Таблицы.ОстаткиТовараВТаре>@ as dv 
83
+	on dv.ХАРАКТЕРИСТИКА = xar.Ссылка 
84
+	AND dv.КАЧЕСТВО = 'НОВЫЙ' 
85
+	AND dv.ТАРА = [tara_t]
86
+left join @<таблицы.значениясвойств>@ as ssv_с 
87
+	on ssv_с.объект = xar.Ссылка 
88
+	and ssv_с.свойство = (Select MAX(ссылка) From @<Справочники.НаименованияСвойств>@ Where наименование = 'Цвет')
89
+left join @<Справочники.ЗначенияСвойств>@ as c_name on c_name.Ссылка = ssv_с.Значение
90
+left join @<таблицы.значениясвойств>@ as ssv_s 
91
+	on ssv_s.объект = xar.Ссылка  
92
+	and ssv_s.свойство = (Select MAX(ссылка) From @<Справочники.НаименованияСвойств>@ Where наименование = 'Размер')
93
+left join @<Справочники.ЗначенияСвойств>@ as s_name on s_name.Ссылка = ssv_s.Значение
94
+left join ost[report_ref] as ost on ost.НОМЕНКЛАТУРА = pr.НОМЕНКЛАТУРА
95
+left join tablici_prajsi as pr_plan_nom 
96
+	on pr_plan_nom.Номенклатура=nom.ссылка 
97
+	and pr_plan_nom.ТипЦены='[PlanPriceType]' 
98
+	and pr_plan_nom.Характеристика=0
99
+left join tablici_prajsi as pr_plan_xxar 
100
+	on pr_plan_xxar.Номенклатура=nom.ссылка 
101
+	and pr_plan_xxar.ТипЦены='[PlanPriceType]' 
102
+	and pr_plan_xxar.Характеристика=xar.ссылка 
103
+	and pr_plan_xxar.Дата>=IFNULL(pr_plan_nom.Дата,pr_plan_xxar.Дата)
104
+Where pr.ДАТА BETWEEN '[DateFrom]' AND '[DateTo]'
105
+AND pr.ТИПЦЕНЫ IN ({price_col.Тип_цены_ссылка}, {price_col.Тип_цены_базовый_ссылка})
106
+AND pr.КАЧЕСТВО = 'НОВЫЙ'
107
+Group by
108
+	pr.НОМЕНКЛАТУРА
109
+	,IFNULL(c_name.Наименование, '*')
110
+Having
111
+	`Остаток_арт_цвет`;
112
+#query
113
+#endsrc
114
+#set nl=@{alter table report[report_ref] add index(Ссылка)}@
115
+#se hashed=[DateFrom]-[DateTo]
116
+
117
+Select
118
+	CONCAT(report.Артикул,'/',report.Цвет,'/',report.ДОКУМЕНТ,'/',report.Цена_новая) AS 'pos_id'
119
+	,report.Ссылка as 'h::Ссылка'
120
+	,report.Номенклатура
121
+	,report.Дата_цены as 'Дата цены'
122
+	,report.Сектор as 'Сектор'
123
+	,report.Группа as 'Группа'
124
+	,report.Наименование as 'Наименование'
125
+	,report.Артикул as 'Артикул'
126
+	,report.Фото as 'Фото'
127
+	,report.Фото_link as 'Фото_link'
128
+	,report.Цвет as 'Цвет'
129
+	,report.Размер as 'Размер'
130
+	,report.Коды as 'Коды'
131
+	,report.Цена_новая as 'Цена новая'
132
+	,report.Цена_план as 'Цена план'
133
+	,if (report.Цена_план > report.Цена_новая , -1, 1) * abs( ROUND(((report.Цена_план - report.Цена_новая) / report.Цена_план) * 100)) as 'Скидка, %'
134
+	,report.Ценник as 'Ценник'
135
+	,report.Остаток_арт_цвет as 'Остаток (арт.+цвет)'
136
+	,IF(IFNULL(cpr.ССЫЛКА, 0), IFNULL(cpr.ДатаИзменения,'X'), '') as 'Выполнено (Дата)'
137
+	,IF(cpr.ССЫЛКА, true, false) as 'done'
138
+	,IFNULL(cpr.ССЫЛКА, 0) as 'h::Выполнено'
139
+	,report.ДОКУМЕНТ as 'h::ДОКУМЕНТ'
140
+	,cpr.ДатаИзменения as 'done_updated'
141
+From report[report_ref] as report
142
+left join [const_pereocenka_report] as cpr 
143
+	on cpr.ДОКУМЕНТ = report.ДОКУМЕНТ 
144
+	AND cpr.АРТИКУЛ = report.АРТИКУЛ 
145
+	AND cpr.ЦВЕТ = report.ЦВЕТ 
146
+	AND cpr.ЦЕНА = report.Цена_новая
147
+;HAVING `Скидка, %` <> 0
148
+Order by
149
+	`Цена новая` DESC
150
+	,`Группа`
151
+	,`Артикул`
152
+	,`h::Выполнено` = '' DESC
153
+#endproc

Loading…
Отказ
Запис