def get_internal_shipment(params): shipment_id = params.get('id') reference = params.get('reference') if shipment_id: url = f'{FULFIL_API_URL}/model/stock.shipment.internal/{shipment_id}' response = requests.get(url, headers=headers) if response.status_code == 200: return response.json() send_email("Fulfil: failed to get internal shipment", f"Failed to get IS with {shipment_id} ID") elif reference: url = f'{FULFIL_API_URL}/model/stock.shipment.internal?reference={reference}' response = requests.get(url, headers=headers) if response.status_code == 200: return response.json()[0] send_email("Fulfil: failed to get internal shipment", f"Failed to get {reference} IS") return None
def check_request_signature(request): try: webhook_secret = 'f5d0c396ba09b4c2'.encode('utf-8') headers = request.headers signature = headers.get("X-Loop-Signature", '') body = request.raw_body hashed = hmac.new(webhook_secret, body, hashlib.sha256) decoded = base64.b64encode(hashed.digest()).decode() if decoded == signature: return True else: send_email(subject="loopreturns: signature, error", content=f"{body}\n{signature}", dev_recipients=True) except Exception as e: print("check_request_signature error") traceback.print_exc() try: print(headers) print(body) print(signature) print(decoded) except: pass
def notify_end_up_boxes(few_boxes): info = str(listDictsToHTMLTable(few_boxes)) send_email( f"Boxes are ending up", f"{date.today().strftime('%Y-%m-%d')}<br>" + info, dev_recipients=True, email=['*****@*****.**'], )
def check_products(self, products): for key, value in products.items(): if self.ruby_quantities[key] < value: send_email( "!!!IMPORTANT: Internal shipments (product check result)", f"problem with {key} created internal shipment " f"with values ({value}) more then available " f"on rubyhas {self.ruby_quantities[key]}", dev_recipients=True) products[key] = self.ruby_quantities[key]
def capture_error(error, data=None, email=None, **tags): tags.setdefault('environment', EVIRONMENT) with configure_scope() as scope: for tag, value in tags.items(): scope.set_tag(tag, value) if data: sentry_sdk.set_context('DATA', data) capture_exception(error, scope=scope) if email: send_email(error, str(data), email=email)
def find_late_orders(): from app import BASE_DIR days_delay = 2 emails = get_n_days_old_orders(days_delay, late=True) template = Template( open(f'{BASE_DIR}/chalicelib/template/late_order.html').read()) if emails: late_orders_report = [] for sale in emails: shipment, email_type, moves, planned_date = get_oldest_shipment( sale) if planned_date in dates_with_passed_some_work_days(days_delay) \ and (shipment['shipping_instructions'] == None or 'Planned date delayed' not in shipment['shipping_instructions']): report = { 'Shopify Order': sale['reference'], 'Customer Name': sale['party.name'], 'Customer Email': sale['party.email'], 'Planned Date Changed': 'No', } data = { 'YEAR': str(date.today().year), 'FINISH_DATE': planned_date, # 'TRACK_LINK': get_link(sale['reference']), 'items': moves, 'TEXT': LATE_ORDER_TEXT[email_type] } result = template.render(**data) send_email( f"A small hiccup on our end", result, email=sale['party.email'], # email=['*****@*****.**'], # dev_recipients=True, from_email='*****@*****.**', ) # break if email_type in ['mto', 'vermeil']: update_planned_date(shipment, email_type) report['Planned Date Changed'] = 'Yes' late_orders_report.append(report) if late_orders_report: send_email( f"Fulfil: found {len(late_orders_report)} late orders", str(listDictsToHTMLTable(late_orders_report)), email=['*****@*****.**', '*****@*****.**'], # email=['*****@*****.**'], dev_recipients=True)
def process_boxes(): shipments = collect_info() get_boxes() col_boxes = collect_boxes(shipments) updated_sku_by_warehouse = sku_for_update(col_boxes) try: sku_for_report = [] count = 'Nothing changed' for storage, updated_sku in updated_sku_by_warehouse.items(): sku_for_report.extend(updated_sku) count = new_inventory(updated_sku, storage) complete_inventory(count) confirm_inventory(count) add_box_comment(shipments) info = str(listDictsToHTMLTable(sku_for_report)) info += f'<br> processed CS {[item["rec_name"] for item in shipments]}' send_email( f"Fullfill: Sync boxes", f"{date.today().strftime('%Y-%m-%d')}, done. Inventory id {count}<br>" + info, dev_recipients=True, email=['*****@*****.**'], ) except Exception as e: info = str(listDictsToHTMLTable(sku_for_report)) info += f'processed CS {[item["rec_name"] for item in shipments]}' send_email( f"Fullfill: Sync boxes Fail", f"{date.today().strftime('%Y-%m-%d')}, fail <br>" + info, dev_recipients=True, email=['*****@*****.**'], ) print(traceback.format_exc())
def send_email(self): if self.message: send_email(f"Fulfil Report: Internal shipments automatic", self.message, email=['*****@*****.**'], dev_recipients=True)
def email_report(): db_ref = get_db() records = db_ref.fetch_report_data() email.send_email(records)
}, 'reminder': { 'subject': 'About that warranty claim', 'data': { 'PREH': 'Reminder!', 'HEADER': 'Request Approved!', 'LINK_TEXT': 'NEXT STEPS', 'TEXT': ''' We’ve approved your repair request and ready to receive it. Use the link below and fill the tracking number to track your parcel. ''', } }, } def send_repearment_email(email, case, NOTE=None, DT=None): from app import BASE_DIR info = REPEARMENT_CASE[case] if DT: LINK = f"https://warrantyclaims.auratenewyork.com/info?DT={DT}" info['data']['LINK'] = LINK template = Template( open(f'{BASE_DIR}/chalicelib/template/notification.html').read()) content = template.render(**info['data'], **{"NOTE": NOTE},) send_email(info['subject'], content, email=email, dev_recipients=False, from_email='*****@*****.**')
def return_created(body): errors = [] Model = client.model('sale.sale') sale = Model.search_read_all( domain=[["AND", ["reference", "=", body['order_name']]]], order=None, fields=['id', 'lines'], # batch_size=5, ) sale = list(sale) if not sale: errors.append( f"Can't create return, didn't find any sale with reference {body['order_name']}" ) return errors sale = sale[0] Model = client.model('sale.line') f_lines = Model.search_read_all( domain=[["AND", ["id", "in", sale['lines']]]], order=None, fields=['product', 'product.code', 'quantity'], ) f_lines = list(f_lines) if not f_lines: errors.append( f"Can't create return, didn't find any sale lines with reference {body['order_name']}" ) return errors order_id = sale['id'] url = f'{get_fulfil_model_url("sale.sale")}/{order_id}/return_order' lines = [] for body_l in body['line_items']: ll = filter(lambda x: x['product.code'] == body_l['sku'], f_lines) if not ll: errors.append(f"Line not found {body_l}\n") continue line = ll.__next__() line_id = line['id'] lines.append({ # Optional fields on line # ================== # "return_quantity": body_l[''], # defaults to the order line returnable quantity # "unit_price": "320.45", # defaults to the original order line unit price. Change this amount if the refund is not the full amount of the original order line. # If the return was created on an external returns platform, # the ID of the line # "order_line_id": line_id, # "channel_identifier": body_l['line_item_id'], # "return_reason": body_l["return_reason"], # Created if not exists # "note": "tracking_number " + body['tracking_number'], "note": body_l['return_comment'], "return_quantity": 1, "order_line_id": line_id, "channel_identifier": body_l['line_item_id'], "return_reason": body_l["return_reason"], # Created if not exists }) if not lines: errors.append("Can't create return, didn't find any line") return errors if body['exchanges']: Model = client.model('product.product') # # exchanges created through shopify # for i, item in enumerate(body['exchanges']): # if len(lines) > i: # product = Model.search_read_all( # domain=[["AND", ["code", "=", item['sku']]]], # order=None, # fields=['id'], # ) # product_id = product.__next__()['id'] # lines[i]['exchange_quantity'] = 1 # lines[i]['exchange_product'] = product_id # lines[i]['exchange_unit_price'] = item['total'] # # # Exchange fields # # # ================== # # # +ve quantity of replacement item to ship to customer # # "exchange_quantity": 1, # # # ID of the product being sent. # # # If replacement item is not specified, the same outbound item will be shipped. # # "exchange_product": 1234, # # # If the unit price is not specified, the unit price of the exchanged item is used. # # "exchange_unit_price": "320.45", # Unit price for outbound item # else: # errors.append(f"failed to add exchange for {item}\n " # f"there is more exchanges than returns") # break payload = [{ "channel_identifier": body[ 'id'], # Unique identifier for the return in the channel. This will be used as idempotency key to avoid duplication. "reference": 'return-' + body["order_name"], # Return order reference, RMA "lines": lines, "warehouse": 140, }] response = requests.put(url, json=payload, headers=headers) if response.status_code != 200: content = f''' error response from fullfill: {response.status_code}<br/> text: {response.text}<br/> url {url}<br/> payload: <br/> {json.dumps(payload)} ''' send_email("Loop webhook error!!!!", content, dev_recipients=True) return response.text, errors