def get_calendar_events(self, user_id): from frappe.core.doctype.event.event import get_events events = get_events(self.future_from_date.strftime("%Y-%m-%d"), self.future_to_date.strftime("%Y-%m-%d")) html = "" if events: for i, e in enumerate(events): if i >= 10: break if e.all_day: html += """<li style='line-height: 200%%'>%s [%s (%s)]</li>""" % ( e.subject, datetime_in_user_format(e.starts_on), _("All Day"), ) else: html += "<li style='line-height: 200%%'>%s [%s - %s]</li>" % ( e.subject, datetime_in_user_format(e.starts_on), datetime_in_user_format(e.ends_on), ) if html: return 1, "<h4>Upcoming Calendar Events (max 10):</h4><ul>" + html + "</ul><hr>" else: return 0, "<p>Calendar Events</p>"
def validate_return_reference_doc(self): """validate item with reference doc""" ref = get_return_doc_and_details(self) if ref.doc: # validate docstatus if ref.doc.docstatus != 1: frappe.throw( _("{0} {1} must be submitted").format( ref.doc.doctype, ref.doc.name), frappe.InvalidStatusError) # update stock check if ref.doc.doctype == "Sales Invoice" and cint( ref.doc.update_stock) != 1: frappe.throw( _("'Update Stock' for Sales Invoice {0} must be set"). format(ref.doc.name), NotUpdateStockError) # posting date check ref_posting_datetime = "%s %s" % (cstr( ref.doc.posting_date), cstr(ref.doc.posting_time) or "00:00:00") this_posting_datetime = "%s %s" % (cstr( self.posting_date), cstr(self.posting_time)) if this_posting_datetime < ref_posting_datetime: from frappe.utils.dateutils import datetime_in_user_format frappe.throw( _("Posting timestamp must be after {0}").format( datetime_in_user_format(ref_posting_datetime))) stock_items = get_stock_items_for_return(ref.doc, ref.parentfields) already_returned_item_qty = self.get_already_returned_item_qty( ref.fieldname) for item in self.get("mtn_details"): # validate if item exists in the ref doc and that it is a stock item if item.item_code not in stock_items: frappe.throw( _("Item {0} does not exist in {1} {2}").format( item.item_code, ref.doc.doctype, ref.doc.name), frappe.DoesNotExistError) # validate quantity <= ref item's qty - qty already returned ref_item = ref.doc.getone({"item_code": item.item_code}) returnable_qty = ref_item.qty - flt( already_returned_item_qty.get(item.item_code)) if not returnable_qty: frappe.throw( _("Item {0} has already been returned").format( item.item_code), StockOverReturnError) elif item.transfer_qty > returnable_qty: frappe.throw( _("Cannot return more than {0} for Item {1}").format( returnable_qty, item.item_code), StockOverReturnError)
def get_calendar_events(self, user_id): from frappe.core.doctype.event.event import get_events events = get_events(self.future_from_date.strftime("%Y-%m-%d"), self.future_to_date.strftime("%Y-%m-%d")) html = "" if events: for i, e in enumerate(events): if i>=10: break if e.all_day: html += """<li style='line-height: 200%%'>%s [%s (%s)]</li>""" % \ (e.subject, datetime_in_user_format(e.starts_on), _("All Day")) else: html += "<li style='line-height: 200%%'>%s [%s - %s]</li>" % \ (e.subject, datetime_in_user_format(e.starts_on), datetime_in_user_format(e.ends_on)) if html: return 1, "<h4>" + _("Upcoming Calendar Events (max 10)") + ":</h4><ul>" + html + "</ul><hr>" else: return 0, "<p>" + _("Calendar Events") + "</p>"
def validate_return_reference_doc(self): """validate item with reference doc""" ref = get_return_doclist_and_details(self.doc.fields) if ref.doclist: # validate docstatus if ref.doclist[0].docstatus != 1: frappe.msgprint(_(ref.doclist[0].doctype) + ' "' + ref.doclist[0].name + '": ' + _("Status should be Submitted"), raise_exception=frappe.InvalidStatusError) # update stock check if ref.doclist[0].doctype == "Sales Invoice" and cint(ref.doclist[0].update_stock) != 1: frappe.msgprint(_(ref.doclist[0].doctype) + ' "' + ref.doclist[0].name + '": ' + _("Update Stock should be checked."), raise_exception=NotUpdateStockError) # posting date check ref_posting_datetime = "%s %s" % (cstr(ref.doclist[0].posting_date), cstr(ref.doclist[0].posting_time) or "00:00:00") this_posting_datetime = "%s %s" % (cstr(self.doc.posting_date), cstr(self.doc.posting_time)) if this_posting_datetime < ref_posting_datetime: from frappe.utils.dateutils import datetime_in_user_format frappe.msgprint(_("Posting Date Time cannot be before") + ": " + datetime_in_user_format(ref_posting_datetime), raise_exception=True) stock_items = get_stock_items_for_return(ref.doclist, ref.parentfields) already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname) for item in self.doclist.get({"parentfield": "mtn_details"}): # validate if item exists in the ref doclist and that it is a stock item if item.item_code not in stock_items: msgprint(_("Item") + ': "' + item.item_code + _("\" does not exist in ") + ref.doclist[0].doctype + ": " + ref.doclist[0].name, raise_exception=frappe.DoesNotExistError) # validate quantity <= ref item's qty - qty already returned ref_item = ref.doclist.getone({"item_code": item.item_code}) returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code)) if not returnable_qty: frappe.throw("{item}: {item_code} {returned}".format( item=_("Item"), item_code=item.item_code, returned=_("already returned though some other documents")), StockOverReturnError) elif item.transfer_qty > returnable_qty: frappe.throw("{item}: {item_code}, {returned}: {qty}".format( item=_("Item"), item_code=item.item_code, returned=_("Max Returnable Qty"), qty=returnable_qty), StockOverReturnError)
def track_packages(): # track packages and update the status # get all the packing_slips name date_format = convert_user_date_format() now = dt.strptime(datetime_in_user_format(dt.now()), date_format) #scheduler_events should run on 8AM, 12PM, and 5PM condition = ( (now > now.replace(hour=8, minute=0, second=0, microsecond=0) and now < now.replace(hour=9, minute=0, second=0, microsecond=0)) or (now > now.replace(hour=12, minute=0, second=0, microsecond=0) and now < now.replace(hour=13, minute=0, second=0, microsecond=0)) or (now > now.replace(hour=17, minute=0, second=0, microsecond=0) and now < now.replace(hour=18, minute=0, second=0, microsecond=0))) if condition: query = """SELECT DISTINCT ps.delivery_note, ps.name, ps.tracking_id FROM `tabPacking Slip` ps,`tabDelivery Note` dn WHERE ps.docstatus=1 AND dn.docstatus=1 AND dn.is_manual_shipping = 0 AND ps.tracking_status<>'Delivered' AND ps.delivery_note=dn.name""" packing_slips = frappe.db.sql(query, as_dict=True) for ps in packing_slips: status = get_package_tracking_status(ps.get("tracking_id")) # status = get_package_tracking_status("5932428095") # status = get_package_tracking_status("990728071") # In Transit # status = get_package_tracking_status("1Z12345E0291980793") # Delivered if status: code = status.get("code") # update status ps_name = ps.get("name") description = status.get("description").capitalize() query = """UPDATE `tabPacking Slip` SET tracking_status='%s' WHERE name='%s'""" % (description, ps_name) frappe.db.sql(query) query = """UPDATE `tabPacking Slip Details` SET tracking_status='%s' WHERE parent='%s' AND packing_slip='%s'""" % ( description, ps.get("delivery_note"), ps_name) frappe.db.sql(query) if code == "I": si = make_sales_invoice( source_name=ps.get("delivery_note"), target_doc=None) si.save(ignore_permissions=True) create_todo(si.name, ps.get("delivery_note"))
def track_packages(): # track packages and update the status # get all the packing_slips name date_format = convert_user_date_format() now = dt.strptime(datetime_in_user_format(dt.now()), date_format) #scheduler_events should run on 8AM, 12PM, and 5PM condition = ((now > now.replace(hour=8, minute=0, second=0, microsecond=0) and now < now.replace(hour=9, minute=0, second=0, microsecond=0)) or (now > now.replace(hour=12, minute=0, second=0, microsecond=0) and now < now.replace(hour=13, minute=0, second=0, microsecond=0)) or (now > now.replace(hour=17, minute=0, second=0, microsecond=0) and now < now.replace(hour=18, minute=0, second=0, microsecond=0))) if condition: query = """SELECT DISTINCT ps.delivery_note, ps.name, ps.tracking_id FROM `tabPacking Slip` ps,`tabDelivery Note` dn WHERE ps.docstatus=1 AND dn.docstatus=1 AND dn.is_manual_shipping = 0 AND ps.tracking_status<>'Delivered' AND ps.delivery_note=dn.name""" packing_slips = frappe.db.sql(query,as_dict=True) for ps in packing_slips: status = get_package_tracking_status(ps.get("tracking_id")) # status = get_package_tracking_status("5932428095") # status = get_package_tracking_status("990728071") # In Transit # status = get_package_tracking_status("1Z12345E0291980793") # Delivered if status: code = status.get("code") # update status ps_name = ps.get("name") description = status.get("description").capitalize() query = """UPDATE `tabPacking Slip` SET tracking_status='%s' WHERE name='%s'"""%(description, ps_name) frappe.db.sql(query) query = """UPDATE `tabPacking Slip Details` SET tracking_status='%s' WHERE parent='%s' AND packing_slip='%s'"""%(description, ps.get("delivery_note"),ps_name) frappe.db.sql(query) if code == "I": si = make_sales_invoice(source_name=ps.get("delivery_note"), target_doc=None) si.save(ignore_permissions=True) create_todo(si.name, ps.get("delivery_note"))
def validate_return_reference_doc(self): """validate item with reference doc""" ref = get_return_doc_and_details(self) if ref.doc: # validate docstatus if ref.doc.docstatus != 1: frappe.throw(_("{0} {1} must be submitted").format(ref.doc.doctype, ref.doc.name), frappe.InvalidStatusError) # update stock check if ref.doc.doctype == "Sales Invoice" and cint(ref.doc.update_stock) != 1: frappe.throw(_("'Update Stock' for Sales Invoice {0} must be set").format(ref.doc.name), NotUpdateStockError) # posting date check ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00") this_posting_datetime = "%s %s" % (self.posting_date, self.posting_time) if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime): from frappe.utils.dateutils import datetime_in_user_format frappe.throw(_("Posting timestamp must be after {0}") .format(datetime_in_user_format(ref_posting_datetime))) stock_items = get_stock_items_for_return(ref.doc, ref.parentfields) already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname) for item in self.get("items"): # validate if item exists in the ref doc and that it is a stock item if item.item_code not in stock_items: frappe.throw(_("Item {0} does not exist in {1} {2}").format(item.item_code, ref.doc.doctype, ref.doc.name), frappe.DoesNotExistError) # validate quantity <= ref item's qty - qty already returned if self.purpose == "Purchase Return": ref_item_qty = sum([flt(d.qty)*flt(d.conversion_factor) for d in ref.doc.get({"item_code": item.item_code})]) elif self.purpose == "Sales Return": ref_item_qty = sum([flt(d.qty) for d in ref.doc.get({"item_code": item.item_code})]) returnable_qty = ref_item_qty - flt(already_returned_item_qty.get(item.item_code)) if not returnable_qty: frappe.throw(_("Item {0} has already been returned").format(item.item_code), StockOverReturnError) elif item.transfer_qty > returnable_qty: frappe.throw(_("Cannot return more than {0} for Item {1}").format(returnable_qty, item.item_code), StockOverReturnError)
def set_calendar_invite(self, part): from icalendar import Calendar, Event cal = Calendar.from_ical(self.get_payload(part)) start_format = "%a %b %d %H:%M" end_format = "%H:%M" # only hour needed for end time text_content = "" for component in cal.walk('vevent'): event = component.get('summary') description = component.get('description') location = component.get('location') end = component.get('dtend') from frappe.utils.dateutils import datetime_in_user_format start = datetime_in_user_format(component.get('dtstart').dt) total_time = "%s-%s" % (start, end.dt.strftime(end_format)) text_content += "Calendar Invite\n\n Summary: %s \n\nDescription: %s \n\nLocation: %s \n\nTime: %s \n\n------\n\n " % (event, description, location, total_time) self.text_content += text_content self.html_content += markdown(text_content)