Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

263 wiersze
10 KiB

  1. from __future__ import unicode_literals
  2. from erpnext.controllers.accounts_controller import get_taxes_and_charges
  3. from erpnext.accounts.party import get_due_date
  4. from frappe.utils import add_days, today, add_months
  5. import frappe
  6. import frappe.permissions
  7. import frappe.share
  8. import json
  9. import traceback
  10. from frappe import _
  11. @frappe.whitelist()
  12. def app_error_log(title, error):
  13. d = frappe.get_doc(
  14. {
  15. "doctype": "Custom Error Log",
  16. "title": str("User:") + str(title),
  17. "error": traceback.format_exc(),
  18. }
  19. )
  20. d = d.insert(ignore_permissions=True)
  21. return d
  22. @frappe.whitelist()
  23. def makeInvoice(
  24. date,
  25. customer,
  26. items,
  27. currency=None,
  28. lease=None,
  29. lease_item=None,
  30. qty=None,
  31. schedule_start_date=None,
  32. doctype="Sales Invoice", # Allow to create Sales Invoice or Sales Order
  33. ):
  34. """Create sales invoice from lease invoice schedule."""
  35. if not doctype:
  36. doctype = "Sales Invoice"
  37. try:
  38. if not customer:
  39. frappe.throw(_("Please select a Customer in Lease {0}").format(lease))
  40. company = frappe.get_value("Lease", lease, "company")
  41. default_tax_template = frappe.get_value(
  42. "Company", company, "default_tax_template"
  43. )
  44. if qty != int(qty):
  45. # it means the last invoice for the lease that may have fraction of months
  46. subs_end_date = frappe.get_value("Lease", lease, "end_date")
  47. else:
  48. # month qty is not fractional
  49. subs_end_date = add_days(add_months(schedule_start_date, qty), -1)
  50. doc = frappe.get_doc(
  51. dict(
  52. doctype=doctype,
  53. company=company,
  54. posting_date=today(),
  55. items=json.loads(items),
  56. customer=str(customer),
  57. due_date=getDueDate(today(), str(customer)),
  58. currency=currency,
  59. lease=lease,
  60. lease_item=lease_item,
  61. taxes_and_charges=default_tax_template,
  62. from_date=schedule_start_date,
  63. to_date=subs_end_date,
  64. cost_center=getCostCenter(lease),
  65. )
  66. )
  67. if doc.doctype == "Sales Order":
  68. doc.delivery_date = doc.to_date
  69. doc.insert()
  70. if doc.taxes_and_charges:
  71. getTax(doc)
  72. doc.calculate_taxes_and_totals()
  73. # frappe.msgprint("Department " + str(sales_invoice.department))
  74. doc.save()
  75. return doc
  76. except Exception as e:
  77. app_error_log(frappe.session.user, str(e))
  78. @frappe.whitelist()
  79. def getTax(sales_invoice):
  80. taxes = get_taxes_and_charges(
  81. "Sales Taxes and Charges Template", sales_invoice.taxes_and_charges
  82. )
  83. for tax in taxes:
  84. sales_invoice.append("taxes", tax)
  85. @frappe.whitelist()
  86. def getDueDate(date, customer):
  87. return get_due_date(
  88. date,
  89. "Customer",
  90. str(customer),
  91. frappe.db.get_single_value("Global Defaults", "default_company"),
  92. date,
  93. )
  94. @frappe.whitelist()
  95. def getCostCenter(name):
  96. property_name = frappe.db.get_value("Lease", name, "property")
  97. return frappe.db.get_value("Property", property_name, "cost_center")
  98. @frappe.whitelist()
  99. def leaseInvoiceAutoCreate():
  100. """Prepare data to create sales invoice from lease invoice schedule. This is called from form button as well as daily schedule"""
  101. try:
  102. # frappe.msgprint("Started")
  103. invoice_start_date = frappe.db.get_single_value(
  104. "Property Management Settings", "invoice_start_date"
  105. )
  106. lease_invoice = frappe.get_all(
  107. "Lease Invoice Schedule",
  108. filters={
  109. "date_to_invoice": ["between", (invoice_start_date, today())],
  110. "invoice_number": "",
  111. },
  112. fields=[
  113. "name",
  114. "date_to_invoice",
  115. "invoice_number",
  116. "parent",
  117. "parent",
  118. "invoice_item_group",
  119. "lease_item",
  120. "paid_by",
  121. "currency",
  122. ],
  123. order_by="parent, paid_by, invoice_item_group, date_to_invoice, currency, lease_item",
  124. )
  125. # frappe.msgprint("Lease being generated for " + str(lease_invoice))
  126. row_num = 1 # to identify the 1st line of the list
  127. prev_parent = ""
  128. prev_customer = ""
  129. prev_invoice_item_group = ""
  130. prev_date_to_invoice = ""
  131. lease_invoice_schedule_name = ""
  132. prev_currency = ""
  133. lease_invoice_schedule_list = []
  134. item_dict = []
  135. item_json = {}
  136. # frappe.msgprint(str(lease_invoice))
  137. for row in lease_invoice:
  138. # frappe.msgprint(str(invoice_item.name) + " " + str(invoice_item.lease_item))
  139. # Check if same lease, customer, invoice_item_group and date_to_invoice.
  140. # Also should not be 1st row of the list
  141. # frappe.msgprint(row.parent + " -- " + prev_parent + " -- " + row.paid_by + " -- " + prev_customer + " -- " + row.invoice_item_group + " -- " + prev_invoice_item_group + " -- " + str(row.date_to_invoice) + " -- " + str(prev_date_to_invoice) + " -- " + row.currency + " -- " + prev_currency)
  142. if (
  143. not (
  144. row.parent == prev_parent
  145. and row.paid_by == prev_customer
  146. and row.invoice_item_group == prev_invoice_item_group
  147. and row.date_to_invoice == prev_date_to_invoice
  148. and row.currency == prev_currency
  149. )
  150. and row_num != 1
  151. ):
  152. # frappe.msgprint("Creating invoice for: " + str(item_dict))
  153. res = makeInvoice(
  154. invoice_item.date_to_invoice,
  155. invoice_item.paid_by,
  156. json.dumps(item_dict),
  157. invoice_item.currency,
  158. invoice_item.parent,
  159. invoice_item.lease_item,
  160. invoice_item.qty,
  161. invoice_item.schedule_start_date,
  162. doctype=invoice_item.document_type,
  163. )
  164. # frappe.msgprint("Result: " + str(res))
  165. if res:
  166. # Loop through all list invoice names that were created and update them with same invoice number
  167. for lease_invoice_schedule_name in lease_invoice_schedule_list:
  168. # frappe.msgprint("---")
  169. # frappe.msgprint("The lease invoice schedule " + str(lease_invoice_schedule_name) + " would be updated with invoice number " + str(res.name) )
  170. frappe.db.set_value(
  171. "Lease Invoice Schedule",
  172. lease_invoice_schedule_name,
  173. "invoice_number"
  174. if res.doctype == "Sales Invoice"
  175. else "sales_order_number",
  176. res.name,
  177. )
  178. frappe.msgprint(
  179. "Lease Invoice generated with number: " + str(res.name)
  180. )
  181. item_dict = []
  182. lease_invoice_schedule_list = (
  183. []
  184. ) # reset the list of names of lease_invoice_schedule
  185. item_json = {}
  186. # Now that the invoice would be created if required, load the record for preparing item_dict
  187. invoice_item = frappe.get_doc("Lease Invoice Schedule", row.name)
  188. if not (invoice_item.schedule_start_date):
  189. invoice_item.schedule_start_date = invoice_item.date_to_invoice
  190. lease_end_date = frappe.get_value("Lease", invoice_item.parent, "end_date")
  191. item_json["item_code"] = invoice_item.lease_item
  192. item_json["qty"] = invoice_item.qty
  193. item_json["rate"] = invoice_item.rate
  194. item_json["cost_center"] = getCostCenter(invoice_item.parent)
  195. item_json["withholding_tax_rate"] = invoice_item.tax
  196. # item_json["enable_deferred_revenue"] = 1 # Set it to true
  197. item_json["service_start_date"] = str(invoice_item.schedule_start_date)
  198. if invoice_item.qty != int(invoice_item.qty):
  199. # it means the last invoice for the lease that may have fraction of months
  200. subs_end_date = lease_end_date
  201. else:
  202. # month qty is not fractional
  203. subs_end_date = add_days(
  204. add_months(invoice_item.schedule_start_date, invoice_item.qty), -1
  205. )
  206. item_json["service_end_date"] = str(subs_end_date)
  207. # Append to the dictionary as a dict() so that the values for the new row can be set
  208. item_dict.append(dict(item_json))
  209. lease_invoice_schedule_list.append(invoice_item.name)
  210. # Remember the values for the next round
  211. prev_parent = invoice_item.parent
  212. prev_customer = invoice_item.paid_by
  213. prev_invoice_item_group = invoice_item.invoice_item_group
  214. prev_date_to_invoice = invoice_item.date_to_invoice
  215. prev_currency = invoice_item.currency
  216. row_num += 1 # increment by 1
  217. # Create the last invoice
  218. res = makeInvoice(
  219. invoice_item.date_to_invoice,
  220. invoice_item.paid_by,
  221. json.dumps(item_dict),
  222. invoice_item.currency,
  223. invoice_item.parent,
  224. invoice_item.lease_item,
  225. invoice_item.qty,
  226. invoice_item.schedule_start_date,
  227. doctype=invoice_item.document_type,
  228. )
  229. if res:
  230. # Loop through all list invoice names that were created and update them with same invoice number
  231. for lease_invoice_schedule_name in lease_invoice_schedule_list:
  232. # frappe.msgprint("The lease invoice schedule " + str(lease_invoice_schedule_name) + " would be updated with invoice number " + str(res.name))
  233. frappe.db.set_value(
  234. "Lease Invoice Schedule",
  235. lease_invoice_schedule_name,
  236. "invoice_number"
  237. if res.doctype == "Sales Invoice"
  238. else "sales_order_number",
  239. res.name,
  240. )
  241. frappe.msgprint("Lease Invoice generated with number: " + str(res.name))
  242. except Exception as e:
  243. app_error_log(frappe.session.user, str(e))
  244. @frappe.whitelist()
  245. def test():
  246. return today()