Coverage for api/handlers/orders/cancellation.py: 24%

82 statements  

« prev     ^ index     » next       coverage.py v7.6.2, created at 2024-10-10 03:02 +0300

1import asyncio 

2import datetime 

3from typing import Any 

4 

5from bson import ObjectId 

6from database.integration_1c.savers import remove_from_1c 

7from database.orders import move_order_and_return, update_status_and_return 

8from exceptions import BadParameterHTTPError, NotFoundHTTPError 

9from handlers.authorization.check_role import has_role 

10from handlers.authorization.company_employee_access import ( 

11 flexible_company_assertion_query, 

12) 

13from mongodb import buf_col, orders_col, trash_orders_col 

14from operations.assignment import data_from_assigned, notify_if_assigned 

15from operations.orders import fill_carrier_by_oid_company 

16from services.notifications.director import notification_api 

17from sotrans_models.models.orders.order import ( 

18 OrderDBModel, 

19 OrderStatus, 

20 OrderUpdateModel, 

21) 

22from sotrans_models.models.roles import SotransRole 

23from sotrans_models.models.users import SotransOIDCUserModel 

24from utils.helper import add_prices_to_update, etag_detalizer, get_org_oid 

25 

26cancelled_q = {OrderDBModel.status: OrderStatus.canceled.value} 

27 

28 

29async def on_utilize_canceled( 

30 order_id: ObjectId, 

31) -> dict[str, Any] | OrderDBModel: 

32 return await move_order_and_return( 

33 order_id, 

34 orders_col, 

35 trash_orders_col, 

36 OrderStatus.archived, 

37 cancelled_q, 

38 {OrderDBModel.deleted_at: datetime.datetime.utcnow()}, 

39 ) 

40 

41 

42async def on_move_to_cancel( 

43 order_id: ObjectId, 

44 user: SotransOIDCUserModel, 

45 order: OrderUpdateModel, 

46) -> dict[str, Any] | OrderDBModel: 

47 if not order.cancel_reason: 

48 raise BadParameterHTTPError("отсутствует cancel_reason") 

49 

50 order_found = await orders_col.collection.find_one( 

51 { 

52 "id": order_id, 

53 OrderDBModel.status: { 

54 "$in": [ 

55 os.value 

56 for os in ( 

57 OrderStatus.unverified, 

58 OrderStatus.confirmed, 

59 OrderStatus.reserved, 

60 OrderStatus.active, 

61 ) 

62 ] 

63 }, 

64 } 

65 ) 

66 if not order_found: 

67 raise NotFoundHTTPError("заказ") 

68 order_model = OrderDBModel(**order_found) 

69 if order_model.status == OrderStatus.confirmed and not has_role( 

70 user, SotransRole.company_logistician 

71 ): 

72 org_id = get_org_oid(user) 

73 restriction_q = {OrderDBModel.carrier.id: org_id} 

74 else: 

75 restriction_q = await flexible_company_assertion_query(user) 

76 update_data = await data_from_assigned(order) 

77 etag_q = {"etag": order.etag} if order.etag else {} 

78 updated = await update_status_and_return( 

79 order_id, 

80 OrderStatus.canceled, 

81 set_=update_data 

82 | { 

83 OrderDBModel.cancel_reason: order.cancel_reason, 

84 OrderDBModel.current_stage: None, 

85 "completed_stages": None, 

86 }, 

87 restriction=restriction_q | etag_q, 

88 ) 

89 

90 om = OrderDBModel(**updated) 

91 asyncio.create_task(notification_api.order_canceled(om)) 

92 notification_api.company_order_canceled(om, user.sub) 

93 asyncio.create_task(remove_from_1c(order_id, orders_col.collection_name)) 

94 notify_if_assigned(order, om) 

95 return updated 

96 

97 

98async def on_cancelled_to_exchange( 

99 order_id: ObjectId, order: OrderUpdateModel | None 

100) -> dict[str, Any] | OrderDBModel: 

101 update_data = await data_from_assigned(order) 

102 etag_q = {"etag": order.etag} if order and order.etag else {} 

103 order_in = await orders_col.collection.find_one( 

104 {"id": order_id, OrderDBModel.status: OrderStatus.canceled.value} 

105 | etag_q 

106 ) 

107 if order_in is None: 

108 await etag_detalizer( 

109 orders_col, 

110 etag_q, 

111 {"id": order_id, OrderDBModel.status: OrderStatus.canceled.value}, 

112 ) 

113 raise NotFoundHTTPError("заказ") 

114 auction_end_time_setting = order and order.auction_end_time 

115 if not ( 

116 order_in.get(OrderDBModel.auction_end_time) or auction_end_time_setting 

117 ): 

118 raise BadParameterHTTPError("нет времени завершения аукциона") 

119 osp = order and order.start_price 

120 if not (order_in.get(OrderDBModel.start_price) or osp): 

121 raise BadParameterHTTPError("нет стартовой цены") 

122 if auction_end_time_setting: 

123 update_data[OrderDBModel.auction_end_time] = auction_end_time_setting 

124 update_data[OrderDBModel.start_price] = osp or order_in.get( 

125 OrderDBModel.start_price 

126 ) 

127 add_prices_to_update( 

128 order_in, 

129 update_data, 

130 update_data[OrderDBModel.start_price], 

131 order and order.end_price, 

132 ) 

133 updated = await update_status_and_return( 

134 order_id, 

135 OrderStatus.exchange, 

136 set_=update_data, 

137 restriction=cancelled_q | etag_q, 

138 ) 

139 notify_if_assigned(order, updated) 

140 return updated 

141 

142 

143async def on_cancelled_to_appointment( 

144 order_id: ObjectId, order: OrderUpdateModel | None 

145): 

146 update_data = await data_from_assigned(order) 

147 etag_q = {"etag": order.etag} if order and order.etag else {} 

148 updated = await update_status_and_return( 

149 order_id, 

150 OrderStatus.appointment, 

151 update_data, 

152 restriction=cancelled_q | etag_q, 

153 ) 

154 notify_if_assigned(order, updated) 

155 

156 

157async def on_cancelled_to_confirmed( 

158 order_id: ObjectId, order: OrderUpdateModel 

159): 

160 if not (order.carrier and order.carrier.id): 

161 raise BadParameterHTTPError("нет перевозчика") 

162 order_data = await data_from_assigned(order) 

163 await fill_carrier_by_oid_company(order_data, order) 

164 etag_q = {"etag": order.etag} if order and order.etag else {} 

165 updated = await update_status_and_return( 

166 order_id, 

167 OrderStatus.confirmed, 

168 order_data, 

169 restriction=cancelled_q | etag_q, 

170 ) 

171 um = OrderDBModel(**updated) 

172 notify_if_assigned(order, um) 

173 asyncio.create_task(notification_api.order_confirmed(um)) 

174 

175 

176async def on_cancelled_to_buffer( 

177 order_id: ObjectId, order: OrderUpdateModel | None 

178) -> dict[str, Any] | OrderDBModel: 

179 update_data = await data_from_assigned(order) 

180 updated = await move_order_and_return( 

181 order_id, 

182 orders_col, 

183 buf_col, 

184 OrderStatus.buffer, 

185 cancelled_q, 

186 update_data, 

187 ) 

188 upm = OrderDBModel(**updated) 

189 notify_if_assigned(order, upm) 

190 asyncio.create_task(notification_api.new_in_buffer(upm)) 

191 return upm