Coverage for api/handlers/orders/buffer_orders.py: 16%
143 statements
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-10 03:02 +0300
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-10 03:02 +0300
1import asyncio
2import datetime
3from typing import Any
5from bson import ObjectId
6from database.entity import update_etag_and_text_search
7from database.orders import move_order_and_return
8from exceptions import (
9 BadParameterHTTPError,
10 NoAccessHTTPError,
11 NotFoundHTTPError,
12)
13from handlers.authorization.company_employee_access import (
14 assert_client_assigned,
15 flexible_company_assertion_query,
16)
17from handlers.grabbers.orders import buffer_orders_grabber
18from handlers.misc.clients import on_create_client
19from mongodb import buf_col, orders_col, trash_orders_col
20from operations.assignment import data_from_assigned, notify_if_assigned
21from operations.orders import (
22 create_order_with_second_phase,
23 fill_orders_subsidiary_or_logistician,
24 make_data_update_for_confirmed,
25 patch_operations,
26 pre_process_to_exchange_auction_end_time,
27 prepare_to_create_order,
28)
29from pymongo import ReturnDocument
30from services.notifications.director import notification_api
31from services.recommendations import suggestion_api
32from sotrans_models.models._base import InsertByUUIDModel
33from sotrans_models.models.misc.client import ClientCreateModel
34from sotrans_models.models.orders.order import (
35 OrderCreateModel,
36 OrderDBModel,
37 OrderStatus,
38 OrderUpdateModel,
39)
40from sotrans_models.models.responses import GenericGetListResponse
41from sotrans_models.models.users import SotransOIDCUserModel
42from sotrans_models.utils.text_mappers import get_orders_text_search
43from utils.data_grabber import BaseGetListQueryParams, BaseGetOneQueryParams
44from utils.helper import (
45 add_prices_to_update,
46 check_assigned,
47 clean_empty_objects,
48 etag_detalizer,
49 place_stop_indicies,
50)
53async def on_get_buffer(
54 executor: SotransOIDCUserModel, params: BaseGetListQueryParams
55) -> GenericGetListResponse[OrderDBModel]:
56 return await buffer_orders_grabber.get_list(
57 params, executor, clients_assignment_default=True
58 )
61async def on_get_one_from_buffer(
62 executor: SotransOIDCUserModel,
63 order_id: ObjectId,
64 params: BaseGetOneQueryParams,
65):
66 restriction_q = await flexible_company_assertion_query(executor)
67 return await buffer_orders_grabber.get_one_by_id_with_pattern(
68 order_id, params, restriction_q
69 )
72async def on_put_to_exchange(
73 order_id: ObjectId, executor: SotransOIDCUserModel, order: OrderUpdateModel
74):
75 if not order.start_price:
76 raise BadParameterHTTPError("нет начальной цены")
77 restriction_q = await flexible_company_assertion_query(executor)
78 order_data = await buf_col.collection.find_one(
79 {"id": order_id} | restriction_q
80 )
81 if not order_data:
82 raise NotFoundHTTPError("заказ")
83 update_data = await data_from_assigned(order)
84 pre_process_to_exchange_auction_end_time(order_data, order, update_data)
85 add_prices_to_update(
86 order_data, update_data, order.start_price, order.end_price
87 )
88 update_data[OrderDBModel.start_price] = order.start_price
89 updated_order = await move_order_and_return(
90 order_id,
91 buf_col,
92 orders_col,
93 OrderStatus.exchange,
94 restrictions_query=restriction_q,
95 updates=update_data,
96 )
97 asyncio.create_task(
98 suggestion_api.create_target_and_recommendation_order(
99 OrderDBModel(**updated_order)
100 )
101 )
102 notify_if_assigned(order, updated_order)
103 return order
106def check_create_params(
107 order: OrderCreateModel | OrderUpdateModel, assigned: bool
108):
109 if order.carrier and order.carrier.id:
110 if not assigned:
111 raise BadParameterHTTPError("нет ответственных")
112 if order.start_price:
113 raise BadParameterHTTPError("лишняя стартовая цена")
114 elif order.start_price:
115 if not assigned:
116 raise BadParameterHTTPError("нет ответственных")
119async def on_create_order(
120 executor: SotransOIDCUserModel, order: OrderCreateModel
121) -> dict[str, Any] | OrderDBModel:
122 assigned = check_assigned(order)
123 check_create_params(order, assigned)
124 if order.start_price and not order.auction_end_time:
125 raise BadParameterHTTPError("нет времени завершения аукциона")
126 if isinstance(order.client, ClientCreateModel):
127 im_responsible = InsertByUUIDModel(id=executor.sub)
128 if not order.client.responsible:
129 order.client.responsible = [im_responsible]
130 elif im_responsible not in order.client.responsible:
131 order.client.responsible.append(im_responsible)
132 await on_create_client(order.client)
133 else:
134 if not await assert_client_assigned(executor, order.client.id):
135 raise NoAccessHTTPError("клиент")
137 order_data = await prepare_to_create_order(executor, order)
138 if order.end_price or order.start_price:
139 add_prices_to_update(
140 order_data, order_data, order.start_price, order.end_price
141 )
142 if order.carrier and order.carrier.id:
143 await make_data_update_for_confirmed(order_data, order)
144 elif order.start_price:
145 order_data[OrderDBModel.status] = OrderStatus.exchange.value
146 # to appointment if no carrier
147 elif assigned:
148 order_data[OrderDBModel.status] = OrderStatus.appointment.value
149 await fill_orders_subsidiary_or_logistician(order_data, order)
150 if order.carrier and order.carrier.id or order.start_price or assigned:
151 created_model = await create_order_with_second_phase(
152 order_data, orders_col
153 )
154 if order.carrier and order.carrier.id:
155 asyncio.create_task(
156 suggestion_api.create_target_and_recommendation_order(
157 created_model
158 )
159 )
160 asyncio.create_task(
161 notification_api.order_confirmed(created_model)
162 )
163 elif order.start_price:
164 asyncio.create_task(
165 suggestion_api.create_target_and_recommendation_order(
166 created_model, target=False
167 )
168 )
169 notification_api.assignment(created_model)
170 return created_model
171 buffer_created_model = await create_order_with_second_phase(
172 order_data, buf_col
173 )
174 asyncio.create_task(notification_api.new_in_buffer(buffer_created_model))
175 return buffer_created_model
178async def on_put_to_trash(
179 order_id: ObjectId,
180 executor: SotransOIDCUserModel,
181):
182 restriction_q = await flexible_company_assertion_query(executor)
183 return await move_order_and_return(
184 order_id,
185 buf_col,
186 trash_orders_col,
187 OrderStatus.archived,
188 restriction_q,
189 {OrderDBModel.deleted_at: datetime.datetime.utcnow()},
190 )
193async def on_update_order(
194 executor: SotransOIDCUserModel, order_id: ObjectId, order: OrderUpdateModel
195) -> OrderDBModel | dict[str, Any]:
196 assigned = check_assigned(order)
197 check_create_params(order, assigned)
198 restriction_q = await flexible_company_assertion_query(executor)
199 etag_q = {"etag": order.etag} if order.etag else {}
200 order_data = await buf_col.collection.find_one(
201 {"id": order_id} | restriction_q | etag_q
202 )
203 if order_data is None:
204 raise NotFoundHTTPError("заказ")
205 place_stop_indicies(order)
206 up_data = order.model_dump(exclude_unset=True)
207 add_prices_to_update(
208 order_data, up_data, order.start_price, order.end_price
209 )
210 clean_empty_objects(up_data)
211 await patch_operations(update_data=up_data, order=order)
212 if assigned:
213 if order.carrier and order.carrier.id:
214 await make_data_update_for_confirmed(up_data, order)
215 order = await move_order_and_return(
216 order_id,
217 buf_col,
218 orders_col,
219 OrderStatus.confirmed,
220 restriction_q,
221 up_data,
222 )
223 om = OrderDBModel(**order)
224 asyncio.create_task(notification_api.order_confirmed(om))
225 notification_api.assignment(om)
226 return order
227 if order.start_price:
228 pre_process_to_exchange_auction_end_time(
229 order_data, order, up_data
230 )
231 order = await move_order_and_return(
232 order_id,
233 buf_col,
234 orders_col,
235 OrderStatus.exchange,
236 restriction_q,
237 up_data,
238 )
239 notification_api.assignment(OrderDBModel(**order))
240 return order
241 appointed = await move_order_and_return(
242 order_id,
243 buf_col,
244 orders_col,
245 OrderStatus.appointment,
246 restriction_q,
247 up_data,
248 )
249 notification_api.assignment(OrderDBModel(**appointed))
250 return appointed
251 order = await buf_col.collection.find_one_and_update(
252 restriction_q | {"id": order_id} | etag_q,
253 {"$set": up_data},
254 return_document=ReturnDocument.AFTER,
255 )
256 if not order:
257 await etag_detalizer(buf_col, etag_q, restriction_q | {"id": order_id})
258 raise NotFoundHTTPError("заказ")
259 await update_etag_and_text_search(
260 order, buf_col, OrderDBModel, get_orders_text_search
261 )
262 return order
265async def on_assign_subsidiary(
266 order_id: ObjectId,
267 user: SotransOIDCUserModel,
268 order: OrderUpdateModel,
269) -> OrderDBModel | dict[str, Any]:
270 assigned = order.assigned
271 if not (
272 assigned and (assigned.company.subsidiary or assigned.company.employee)
273 ):
274 raise BadParameterHTTPError("нет назначения")
275 update_data = await data_from_assigned(order)
276 end_price = order.end_price
277 if end_price is not None:
278 update_data |= {OrderDBModel.end_price: end_price}
279 add_prices_to_update(
280 update_data,
281 update_data,
282 order.start_price,
283 end_price,
284 )
285 restriction_q = await flexible_company_assertion_query(user)
287 assigned = await move_order_and_return(
288 order_id,
289 buf_col,
290 orders_col,
291 OrderStatus.appointment,
292 restrictions_query={OrderDBModel.status: OrderStatus.buffer.value}
293 | restriction_q,
294 updates=update_data,
295 )
296 if not assigned:
297 raise NotFoundHTTPError("заказ")
298 ao = OrderDBModel(**assigned)
299 notification_api.assignment(ao)
300 return ao