def handle_object(self, n_direction, handler): """Выполнение обработчика по объекту На вход направление интеграции и обработчик объекта, который должен принимать ObjectInfo. После того, как станет известно, что за объект интегрируется, обработчик должен заполнить о нем информацию о ObjectInfo""" obj_info = ObjectInfo() session_id = self._get_session_by_direction(n_direction) try: handler(obj_info) object_id = obj_info.id_external if not object_id: raise AppException("Не указан ИД объекта") # проверим, если в лог не написали нечего, то добавим инфу, что объект загрузился object_log_dict = self._object_log_by_session_dict[session_id] if object_id not in object_log_dict: self.write_info_log(object_id, "OK", n_direction) except AppException as err: object_id = obj_info.id_external if not object_id: object_id = "Неизвестный объект" self.write_error_log(object_id, str(err), n_direction)
def __sync_with_act(self): # создание накладных act_out = self.id_act_out if act_out is None: act_out = StkAct.inset_out_act() act_out.s_desc = "Сформирована от \"" + self.get_head_line() + "\"" act_out.save() self.id_act_out = act_out if act_out.s_state != StkAct.STATE_REGISTERING: raise AppException( "Ошибка синхронизации с расходной накладной. Накладная в неверном состоянии" ) # Формирование списка ТМЦ для накладной self_gds_out_dict = {} def add_qty(id_good, n_qty): if id_good in self_gds_out_dict: self_gds_out_dict[id_good] = self_gds_out_dict[id_good] + n_qty else: self_gds_out_dict[id_good] = n_qty for order_det in TrdOrderDet.objects.filter(id_order=self): add_qty(order_det.id_good_id, order_det.n_qty) act_out.apply_det_data(self_gds_out_dict)
def run_order_integration(request): """Запуск интеграции по всем контурам""" has_errors = False error_text_lines = [] for circuit in IntgCircuit.objects.all(): integrator = None if circuit.s_type == IntgCircuit.TYPE_EBAY: integrator = EbayIntegrator() elif circuit.s_type == IntgCircuit.TYPE_Wix: integrator = WixIntegrator() else: raise AppException('Неизвестный тип контура: ' + circuit.s_type) integrator.run(circuit) # Собиаем информацию о выполненнии if integrator.has_errors(): if not has_errors: has_errors = True error_text_lines = error_text_lines + integrator.get_report() if has_errors: # Переводим текст в html, чтобы норм отобразить return render( request, 'show_text.html', context={'lines': error_text_lines}, ) else: return HttpResponseRedirect(reverse('trd_orders'))
def on_start_run(self): # Получаем параметры подключения if not self.circuit.s_config: raise AppException('Не указана конфигурация подключения контура ' + str(self.circuit)) json_data = json.loads(self.circuit.s_config) self.url = json_data.get('url') self.secret = json_data.get('secret') # Загружаем меппинги self.mapping_goods_dict = GoodMapping.get_by_circuit(self.circuit) self.mapping_delivery_service_dict = DeliverySystemMapping.get_by_circuit(self.circuit)
def roll_back_state(id): # откат состояния with transaction.atomic(): act = StkAct.objects.select_for_update().get(pk=id) if act.s_state == StkAct.STATE_REGISTERING: raise AppException("Ошибка отката накладной. Накладная находится в состоянии Оформляется") act.set_s_state(StkAct.STATE_REGISTERING) act.save() # Обновляем остатки qty_dict: Dict = act.__get_det_qty() StkRemains.apply_changes(qty_dict, act.n_direction * -1)
def insert(id_act, id_good): n_order_max = 0 for det in StkActDet.objects.filter(id_act_id=id_act).filter(id_good_id=id_good): if det.id_good_id == id_good: raise AppException("Позиция с таким ТМЦ и Накладной уже существует") if det.n_order > n_order_max: n_order_max = det.n_order obj = StkActDet() obj.set_id_act(id_act) obj.set_id_good(id_good) obj.set_n_order(n_order_max + 1) return obj
def on_start_run(self): # Получаем параметры подключения if not self.circuit.s_config: raise AppException('Не указана конфигурация подключения контура ' + str(self.circuit)) json_data = json.loads(self.circuit.s_config) self.app_id = json_data.get('appid') self.dev_id = json_data.get('devid') self.cert_id = json_data.get('certid') self.token = json_data.get('token') # Загружаем меппинги self.mapping_goods_dict = GoodMapping.get_by_circuit(self.circuit) self.mapping_delivery_service_dict = DeliverySystemMapping.get_by_circuit( self.circuit)
def apply_form_data(self, changed_act_det_array, deleted_act_det_array): # применение данных из формы редактирования with transaction.atomic(): # блокируем объект if self.id is not None: old_act = StkAct.objects.select_for_update().get(pk = self.id) if old_act.s_state == StkAct.STATE_DONE: raise AppException("Ошибка сохранения накладной. Накладная находится в состоянии Выполнен") self.save() for det in changed_act_det_array: det.id_act = self det.save() for det in deleted_act_det_array: det.delete() StkAct.apply_done_state(self.id)
def roll_back_state(id): # откат состояния with transaction.atomic(): shift_result = MnfShiftResult.objects.select_for_update().get( pk=id) if shift_result.s_state == MnfShiftResult.STATE_REGISTERING: raise AppException( "Ошибка отката отчета. Отчет находится в состоянии Оформляется" ) # Откат накладной act_out = shift_result.id_act act_in = shift_result.id_act_in if act_out is not None: StkAct.roll_back_state(act_out.id) if act_in is not None: StkAct.roll_back_state(act_in.id) shift_result.s_state = MnfShiftResult.STATE_REGISTERING shift_result.save()
def run_order_integration_by_id(request, pk): """Запуск интеграции по одному заказу""" trd_order = TrdOrder.objects.get(pk=pk) for circuit in IntgCircuit.objects.filter( id_trade_system=trd_order.id_trade_system): integrator = None if circuit.s_type == IntgCircuit.TYPE_EBAY: integrator = EbayIntegrator() integrator.run_by_single_order(trd_order.s_reg_num) else: raise AppException('Неизвестный тип контура: ' + circuit.s_type) if integrator.has_errors(): # Переводим текст в html, чтобы норм отобразить return render( request, 'show_text.html', context={'lines': integrator.get_report()}, ) else: return HttpResponseRedirect( reverse('trd_order-detail', args=[str(trd_order.id)]))
def apply_form_data(self, changed_items_array, deleted_items_array, changed_materials_array, deleted_materials_array): # применение данных из формы редактирования with transaction.atomic(): # блокируем объект if self.id is not None: old_obj = MnfShiftResult.objects.select_for_update().get( pk=self.id) if old_obj.s_state == MnfShiftResult.STATE_DONE: raise AppException( "Ошибка сохранения накладной. Накладная находится в состоянии Выполнен" ) self.s_state = MnfShiftResult.STATE_DONE self.save() for det in changed_items_array: det.id_shift_result = self det.save() for det in deleted_items_array: det.delete() for det in changed_materials_array: det.id_shift_result = self det.save() for det in deleted_materials_array: det.delete() # синхронизация с накладной self.__sync_with_act() StkAct.apply_done_state(self.id_act_id) StkAct.apply_done_state(self.id_act_in.id) self.save()
def test_connect(self): #api = Trading(domain='api.sandbox.ebay.com', # appid="AlekseyK-svarogmn-SBX-a23495a34-656da854", devid="897bd038-a619-4206-b7eb-c2ca642b4b37", # certid="SBX-23495a34b3cd-991c-4300-9fc2-8def", token=self.get_token(), config_file=None) api = Trading(domain='api.ebay.com', appid="AlekseyK-svarogmn-PRD-2a292be01-16024d26", devid="897bd038-a619-4206-b7eb-c2ca642b4b37", certid="PRD-a292be012d9f-eb3b-418a-ba77-f0cc", token=self.get_token(), config_file=None) response = api.execute( 'GetOrders', { #'CreateTimeFrom': '2021-10-01T00:05:08.100Z', #'CreateTimeTo': '2021-10-30T18:05:08.100Z', 'OrderIDArray': { 'OrderID': ['26-07500-81214'] }, 'OrderRole': 'Seller', 'OrderStatus': 'Completed' }) time = response.dict()['Timestamp'] order_dict = response.dict()['OrderArray'] order_array = order_dict['Order'] #PaidTime: 2021-10-08T02:13:41.000Z - oplachen #ShippedTime: 2021-10-08T07:24:02.000Z - dostavlen for order in order_array: self.print_order(order) # ИД заказа order_id = order.get('OrderID') # Дата оплаты paid_time = order.get('PaidTime') # Дата отправки shipped_time = order.get('ShippedTime') # Дата доставки actual_delivery_time = None # Дата создания created_time = order.get('CreatedTime') # Получатель shipping_address_name = None # Адрес shipping_address_address = None # Набор трек номеров shipment_tracking_number_set = set() # ПРоданные позиции selled_sku_dict = {} # рассчет даты доставки shipping_service_selected = order.get('ShippingServiceSelected') if shipping_service_selected: shipping_package_info = shipping_service_selected.get( 'ShippingPackageInfo') if shipping_package_info: actual_delivery_time = shipping_package_info.get( 'ActualDeliveryTime') # Расчет адреса shipping_address = order.get('ShippingAddress') if shipping_address: shipping_address_name = shipping_address.get('Name') address_dict = { 'Страна': 'CountryName', 'Почтовый индекс': 'PostalCode', 'Область': 'StateOrProvince', 'Город': 'CityName', 'Улица': 'Street1', 'Улица2': 'Street2', } for key in address_dict: value = shipping_address.get(address_dict[key]) if value: if shipping_address_address: shipping_address_address = shipping_address_address + '\n' else: shipping_address_address = '' shipping_address_address = shipping_address_address + key + ': ' + value # Обработка позиций заказа transaction_array = order.get('TransactionArray') if not transaction_array: raise AppException("Не найден список позиций заказа") transaction = transaction_array.get('Transaction') if not transaction: raise AppException("Не найден список позиций заказа") for trans in transaction: # Расчет трек номера shipping_details = trans.get('ShippingDetails') if shipping_details: shipment_tracking_details = shipping_details.get( 'ShipmentTrackingDetails') if shipment_tracking_details: shipment_tracking_number = shipment_tracking_details.get( 'ShipmentTrackingNumber') if shipment_tracking_number: shipment_tracking_number_set.add( shipment_tracking_number) # Расчет товаров item = trans.get('Item') if item: item_id = item.get('ItemID') sku = item.get('SKU') title = item.get('Title') qty = int(trans.get('QuantityPurchased')) if not sku: raise AppException('Для товара ' + title + 'не указан SKU') if sku in selled_sku_dict: selled_sku_dict[sku] = selled_sku_dict[sku] + qty else: selled_sku_dict[sku] = qty print(order_id) print(created_time) print(paid_time) print(shipped_time) print(actual_delivery_time) print(shipping_address_name) print(shipping_address_address) print(shipment_tracking_number_set) print(selled_sku_dict)
def import_order(self, order, obj_info): """Импорт одного заказа""" # ИД заказа order_id = str(order.get('number')) obj_info.id_external = order_id # Требуется сразу же сохранить новый заказ, т.к. сесии выгрузки запоминают дату последней выгрузки # и получают заказы начиная с даты последней выгрузки. Если сохранять все заказы, то они будут обработаны # новыми сессиями как незавршенные trd_order = TrdOrder.objects.filter(s_reg_num=order_id, id_trade_system=self.circuit.id_trade_system).first() if not trd_order: trd_order = TrdOrder.inset_by_trade_system(self.circuit.id_trade_system, self.s_user) trd_order.set_s_reg_num(order_id) trd_order.save() # Оплачен is_payed = order.get('paymentStatus') == "PAID" # Завершен is_finished = order.get('fulfillmentStatus') == "FULFILLED" # Дата создания created_time = order.get('_dateCreated') # Получатель shipping_address_name = None # Адрес shipping_address_address = None # Набор трек номеров shipment_tracking_number = None # ПРоданные позиции selled_sku_list = [] # Способ доставки delivery_option = None # Расчет адреса shipping_info = order.get('shippingInfo') if shipping_info: delivery_option = shipping_info.get('deliveryOption') shipment_details = shipping_info.get('shipmentDetails') if shipment_details: # Получатель shipping_address_name = str(shipment_details.get('lastName')) + ' ' + str( shipment_details.get('firstName')) address = shipment_details.get('address') if address: # Адрес shipping_address_address = address.get('formatted') # Трек номер fulfillments = order.get('fulfillments') if fulfillments: for fulfillment in fulfillments: tracking_info = fulfillment.get('trackingInfo') if tracking_info: shipment_tracking_number = tracking_info.get('trackingNumber') # Товары line_items = order.get('lineItems') if line_items: for line_item in line_items: gds_id = line_item.get('name') n_qty = line_item.get('quantity') gds_dict = { "id": gds_id, "qty": n_qty } options = line_item.get('options') if options: gds_dict["options"] = [] for option in options: if option.get('selection') == "да": gds_dict["options"].append(option.get("option")) selled_sku_list.append(gds_dict) # установка данных # сначала откатим заказ, т.к. он мог уже внести данные в склад old_state = trd_order.id_state if trd_order.id_state.is_write_off_goods(): trd_order.set_id_state(TrdOrderState.get_start_state().id, self.s_user) trd_order.set_d_reg_date(self.__str_to_date(created_time)) trd_order.set_s_receiver(shipping_address_name) trd_order.set_s_address(shipping_address_address) trd_order.set_s_track_num(shipment_tracking_number) trd_order.save() # Служба доставки if delivery_option: delivery_service = self.mapping_delivery_service_dict.get(delivery_option) if not delivery_service: raise AppException('Для службы доставки '+ delivery_option + ' не настроено сопоставление') trd_order.set_id_delivery_service(delivery_service) else: trd_order.set_id_delivery_service(None) trd_order.save() # Обработка ТМЦ selled_goods_dict = {} for selled_sku in selled_sku_list: external_id = selled_sku["id"] external_qty = selled_sku["qty"] mapping_goods = self.mapping_goods_dict.get(external_id) if not mapping_goods: raise AppException('Для товара '+ external_id + ' не настроено сопоставление') # Сам товар for good, n_qty in mapping_goods[GoodMapping.good_mapping_key()]: if good not in selled_goods_dict: selled_goods_dict[good] = 0 selled_goods_dict[good] = selled_goods_dict[good] + n_qty * external_qty # Опции товара options = selled_sku.get('options') if options: for option in options: mapping_option = mapping_goods[GoodMapping.option_mapping_key()].get(option) if not mapping_option: raise AppException('Для товара ' + external_id + ' не настроено сопоставление опции ' + option) for good, n_qty in mapping_option: if good not in selled_goods_dict: selled_goods_dict[good] = 0 selled_goods_dict[good] = selled_goods_dict[good] + n_qty * external_qty order_det_by_good_dict = {} # индксируем позиции заказа for trd_order_det in TrdOrderDet.objects.filter(id_order=trd_order): order_det_by_good_dict[trd_order_det.id_good] = trd_order_det # удаляем позиции, которых нет for order_det_good in order_det_by_good_dict: if order_det_good not in selled_goods_dict: order_det_by_good_dict[order_det_good].delete() # применяем позиции for selled_goods in selled_goods_dict: trd_order_det = order_det_by_good_dict.get(selled_goods) if not trd_order_det: trd_order_det = TrdOrderDet.insert(trd_order.id, selled_goods.id) trd_order_det.set_n_qty(selled_goods_dict[selled_goods]) trd_order_det.save() trd_order.save() # Обработка состояния state = None if is_finished: # Из Wix нельзя понять, что заказ доставлен. ПОтому если ему вручную # было установлено состояние большее, чем отправлен, то ставим его state = TrdOrderState.objects.filter(n_order=400).first() if old_state.n_order > state.n_order: state = old_state if state: trd_order.set_id_state(state.id, self.s_user)
def set_n_qty(self, value: int): if value < 0: raise AppException('Количество не должно быть отрицательным') self.n_qty = value
def __sync_with_act(self): # создание накладных act_out = self.id_act act_in = self.id_act_in if act_out is None: act_out = StkAct.inset_out_act() act_out.s_desc = "Сформирована от \"" + self.get_head_line() + "\"" act_out.save() self.id_act = act_out if act_out.s_state != StkAct.STATE_REGISTERING: raise AppException( "Ошибка синхронизации с расходной накладной. Накладная в неверном состоянии" ) if act_in is None: act_in = StkAct.inset_in_act() act_in.s_desc = "Сформирована от \"" + self.get_head_line() + "\"" act_in.save() self.id_act_in = act_in if act_in.s_state != StkAct.STATE_REGISTERING: raise AppException( "Ошибка синхронизации с приходной накладной. Накладная в неверном состоянии" ) # Формирование списка ТМЦ для накладной self_gds_out_dict = {} self_gds_in_dict = {} def add_qty(dict, id_good, n_qty): if id_good in dict: dict[id_good] = dict[id_good] + n_qty else: dict[id_good] = n_qty def add_out_qty(id_good, n_qty): add_qty(self_gds_out_dict, id_good, n_qty) def add_in_qty(id_good, n_qty): add_qty(self_gds_in_dict, id_good, n_qty) for shift_result_item in MnfShiftResultItems.objects.filter( id_shift_result=self): # приход add_in_qty(shift_result_item.id_item.id_good_id, shift_result_item.n_qty) # расход for item_det in MnfItemDet.objects.filter( id_item=shift_result_item.id_item): add_out_qty(item_det.id_good_id, item_det.n_qty * shift_result_item.n_qty) for shift_result_material in MnfShiftResultMaterials.objects.filter( id_shift_result=self): add_out_qty(shift_result_material.id_good_id, shift_result_material.n_qty) # обновление позиций act_out.apply_det_data(self_gds_out_dict) act_in.apply_det_data(self_gds_in_dict)
def on_export(self): """Действия выполняемые при экспорте. Требуется переопределить этот метод в наследнике. Метод должен получать список объекто экспорта, и для каждого вызывать handle_object Если импорт не используется, то отключите флаг is_import_enabled""" raise AppException("Не реализован экспорт объектов")
def import_order(self, order, obj_info): """Импорт одного заказа""" # ИД заказа order_id = order.get('OrderID') obj_info.id_external = order_id # Требуется сразу же сохранить новый заказ, т.к. сесии выгрузки запоминают дату последней выгрузки # и получают заказы начиная с даты последней выгрузки. Если сохранять все заказы, то они будут обработаны # новыми сессиями как незавршенные trd_order = TrdOrder.objects.filter( s_reg_num=order_id, id_trade_system=self.circuit.id_trade_system).first() if not trd_order: trd_order = TrdOrder.inset_by_trade_system( self.circuit.id_trade_system, self.s_user) trd_order.set_s_reg_num(order_id) trd_order.save() # Дата оплаты paid_time = order.get('PaidTime') # Дата отправки shipped_time = order.get('ShippedTime') # Дата доставки actual_delivery_time = None # Дата создания created_time = order.get('CreatedTime') # Служба доставки shipping_service_name = None # Получатель shipping_address_name = None # Адрес shipping_address_address = None # Набор трек номеров shipment_tracking_number_set = set() # ПРоданные позиции selled_sku_dict = {} # Получение информации о доставке shipping_service_selected = order.get('ShippingServiceSelected') if shipping_service_selected: shipping_service_name = shipping_service_selected.get( 'ShippingService') shipping_package_info = shipping_service_selected.get( 'ShippingPackageInfo') if shipping_package_info: actual_delivery_time = shipping_package_info.get( 'ActualDeliveryTime') # Расчет адреса shipping_address = order.get('ShippingAddress') if shipping_address: shipping_address_name = shipping_address.get('Name') address_dict = { 'Страна': 'CountryName', 'Почтовый индекс': 'PostalCode', 'Область': 'StateOrProvince', 'Город': 'CityName', 'Улица': 'Street1', 'Улица2': 'Street2', } for key in address_dict: value = shipping_address.get(address_dict[key]) if value: if shipping_address_address: shipping_address_address = shipping_address_address + '\n' else: shipping_address_address = '' shipping_address_address = shipping_address_address + key + ': ' + value # Обработка позиций заказа transaction_array = order.get('TransactionArray') if not transaction_array: raise AppException("Не найден список позиций заказа") transaction = transaction_array.get('Transaction') if not transaction: raise AppException("Не найден список позиций заказа") for trans in transaction: # Расчет трек номера shipping_details = trans.get('ShippingDetails') if shipping_details: shipment_tracking_details = shipping_details.get( 'ShipmentTrackingDetails') if shipment_tracking_details: shipment_tracking_number = shipment_tracking_details.get( 'ShipmentTrackingNumber') if shipment_tracking_number: shipment_tracking_number_set.add( shipment_tracking_number) # Расчет товаров item = trans.get('Item') if item: sku = item.get('SKU') title = item.get('Title') qty = int(trans.get('QuantityPurchased')) if not sku: raise AppException('Для товара ' + title + ' не указан SKU') if sku in selled_sku_dict: selled_sku_dict[sku] = selled_sku_dict[sku] + qty else: selled_sku_dict[sku] = qty # установка данных # сначала откатим заказ, т.к. он мог уже внести данные в склад if trd_order.id_state.is_write_off_goods(): trd_order.set_id_state(TrdOrderState.get_start_state().id, self.s_user) trd_order.set_d_reg_date(self.__str_to_date(created_time)) trd_order.set_s_receiver(shipping_address_name) trd_order.set_s_address(shipping_address_address) trd_order.set_s_track_num(', '.join(shipment_tracking_number_set)) trd_order.save() # Служба доставки if shipping_service_name: delivery_service = self.mapping_delivery_service_dict.get( shipping_service_name) if not delivery_service: raise AppException('Для службы доставки ' + shipping_service_name + ' не настроено сопоставление') trd_order.set_id_delivery_service(delivery_service) else: trd_order.set_id_delivery_service(None) trd_order.save() # Обработка ТМЦ selled_goods_dict = {} for selled_sku in selled_sku_dict: mapping_goods = self.mapping_goods_dict.get(selled_sku) if not mapping_goods: raise AppException('Для SKU ' + selled_sku + ' не настроено сопоставление') for good, n_qty in mapping_goods[GoodMapping.good_mapping_key()]: if good not in selled_goods_dict: selled_goods_dict[good] = 0 selled_goods_dict[good] = selled_goods_dict[ good] + n_qty * selled_sku_dict[selled_sku] order_det_by_good_dict = {} # индксируем позиции заказа for trd_order_det in TrdOrderDet.objects.filter(id_order=trd_order): order_det_by_good_dict[trd_order_det.id_good] = trd_order_det # удаляем позиции, которых нет for order_det_good in order_det_by_good_dict: if order_det_good not in selled_goods_dict: order_det_by_good_dict[order_det_good].delete() # применяем позиции for selled_goods in selled_goods_dict: trd_order_det = order_det_by_good_dict.get(selled_goods) if not trd_order_det: trd_order_det = TrdOrderDet.insert(trd_order.id, selled_goods.id) trd_order_det.set_n_qty(selled_goods_dict[selled_goods]) trd_order_det.save() trd_order.save() # Обработка состояния state = None if actual_delivery_time: # Доставлен state = TrdOrderState.objects.filter(n_order=500).first() elif shipped_time: # Отправлен state = TrdOrderState.objects.filter(n_order=400).first() if state: trd_order.set_id_state(state.id, self.s_user)