You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

390 lines
12 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # License: GNU General Public License v3. See license.txt
  3. import frappe
  4. from frappe import _
  5. from frappe.utils import getdate
  6. def get_columns(filters, trans):
  7. validate_filters(filters)
  8. # get conditions for based_on filter cond
  9. based_on_details = based_wise_columns_query(filters.get("based_on"), trans)
  10. # get conditions for periodic filter cond
  11. period_cols, period_select = period_wise_columns_query(filters, trans)
  12. # get conditions for grouping filter cond
  13. group_by_cols = group_wise_column(filters.get("group_by"))
  14. columns = (
  15. based_on_details["based_on_cols"]
  16. + period_cols
  17. + [_("Total(Qty)") + ":Float:120", _("Total(Amt)") + ":Currency:120"]
  18. )
  19. if group_by_cols:
  20. columns = (
  21. based_on_details["based_on_cols"]
  22. + group_by_cols
  23. + period_cols
  24. + [_("Total(Qty)") + ":Float:120", _("Total(Amt)") + ":Currency:120"]
  25. )
  26. conditions = {
  27. "based_on_select": based_on_details["based_on_select"],
  28. "period_wise_select": period_select,
  29. "columns": columns,
  30. "group_by": based_on_details["based_on_group_by"],
  31. "grbc": group_by_cols,
  32. "trans": trans,
  33. "addl_tables": based_on_details["addl_tables"],
  34. "addl_tables_relational_cond": based_on_details.get("addl_tables_relational_cond", ""),
  35. }
  36. return conditions
  37. def validate_filters(filters):
  38. for f in ["Fiscal Year", "Based On", "Period", "Company"]:
  39. if not filters.get(f.lower().replace(" ", "_")):
  40. frappe.throw(_("{0} is mandatory").format(f))
  41. if not frappe.db.exists("Fiscal Year", filters.get("fiscal_year")):
  42. frappe.throw(_("Fiscal Year {0} Does Not Exist").format(filters.get("fiscal_year")))
  43. if filters.get("based_on") == filters.get("group_by"):
  44. frappe.throw(_("'Based On' and 'Group By' can not be same"))
  45. def get_data(filters, conditions):
  46. data = []
  47. inc, cond = "", ""
  48. query_details = conditions["based_on_select"] + conditions["period_wise_select"]
  49. posting_date = "t1.transaction_date"
  50. if conditions.get("trans") in [
  51. "Sales Invoice",
  52. "Purchase Invoice",
  53. "Purchase Receipt",
  54. "Delivery Note",
  55. ]:
  56. posting_date = "t1.posting_date"
  57. if filters.period_based_on:
  58. posting_date = "t1." + filters.period_based_on
  59. if conditions["based_on_select"] in ["t1.project,", "t2.project,"]:
  60. cond = " and " + conditions["based_on_select"][:-1] + " IS Not NULL"
  61. if conditions.get("trans") in ["Sales Order", "Purchase Order"]:
  62. cond += " and t1.status != 'Closed'"
  63. if conditions.get("trans") == "Quotation" and filters.get("group_by") == "Customer":
  64. cond += " and t1.quotation_to = 'Customer'"
  65. year_start_date, year_end_date = frappe.get_cached_value(
  66. "Fiscal Year", filters.get("fiscal_year"), ["year_start_date", "year_end_date"]
  67. )
  68. if filters.get("group_by"):
  69. sel_col = ""
  70. ind = conditions["columns"].index(conditions["grbc"][0])
  71. if filters.get("group_by") == "Item":
  72. sel_col = "t2.item_code"
  73. elif filters.get("group_by") == "Customer":
  74. sel_col = "t1.party_name" if conditions.get("trans") == "Quotation" else "t1.customer"
  75. elif filters.get("group_by") == "Supplier":
  76. sel_col = "t1.supplier"
  77. if filters.get("based_on") in ["Item", "Customer", "Supplier"]:
  78. inc = 2
  79. else:
  80. inc = 1
  81. data1 = frappe.db.sql(
  82. """ select %s from `tab%s` t1, `tab%s Item` t2 %s
  83. where t2.parent = t1.name and t1.company = %s and %s between %s and %s and
  84. t1.docstatus = 1 %s %s
  85. group by %s
  86. """
  87. % (
  88. query_details,
  89. conditions["trans"],
  90. conditions["trans"],
  91. conditions["addl_tables"],
  92. "%s",
  93. posting_date,
  94. "%s",
  95. "%s",
  96. conditions.get("addl_tables_relational_cond"),
  97. cond,
  98. conditions["group_by"],
  99. ),
  100. (filters.get("company"), year_start_date, year_end_date),
  101. as_list=1,
  102. )
  103. for d in range(len(data1)):
  104. # to add blanck column
  105. dt = data1[d]
  106. dt.insert(ind, "")
  107. data.append(dt)
  108. # to get distinct value of col specified by group_by in filter
  109. row = frappe.db.sql(
  110. """select DISTINCT(%s) from `tab%s` t1, `tab%s Item` t2 %s
  111. where t2.parent = t1.name and t1.company = %s and %s between %s and %s
  112. and t1.docstatus = 1 and %s = %s %s %s
  113. """
  114. % (
  115. sel_col,
  116. conditions["trans"],
  117. conditions["trans"],
  118. conditions["addl_tables"],
  119. "%s",
  120. posting_date,
  121. "%s",
  122. "%s",
  123. conditions["group_by"],
  124. "%s",
  125. conditions.get("addl_tables_relational_cond"),
  126. cond,
  127. ),
  128. (filters.get("company"), year_start_date, year_end_date, data1[d][0]),
  129. as_list=1,
  130. )
  131. for i in range(len(row)):
  132. des = ["" for q in range(len(conditions["columns"]))]
  133. # get data for group_by filter
  134. row1 = frappe.db.sql(
  135. """ select %s , %s from `tab%s` t1, `tab%s Item` t2 %s
  136. where t2.parent = t1.name and t1.company = %s and %s between %s and %s
  137. and t1.docstatus = 1 and %s = %s and %s = %s %s %s
  138. """
  139. % (
  140. sel_col,
  141. conditions["period_wise_select"],
  142. conditions["trans"],
  143. conditions["trans"],
  144. conditions["addl_tables"],
  145. "%s",
  146. posting_date,
  147. "%s",
  148. "%s",
  149. sel_col,
  150. "%s",
  151. conditions["group_by"],
  152. "%s",
  153. conditions.get("addl_tables_relational_cond"),
  154. cond,
  155. ),
  156. (filters.get("company"), year_start_date, year_end_date, row[i][0], data1[d][0]),
  157. as_list=1,
  158. )
  159. des[ind] = row[i][0]
  160. for j in range(1, len(conditions["columns"]) - inc):
  161. des[j + inc] = row1[0][j]
  162. data.append(des)
  163. else:
  164. data = frappe.db.sql(
  165. """ select %s from `tab%s` t1, `tab%s Item` t2 %s
  166. where t2.parent = t1.name and t1.company = %s and %s between %s and %s and
  167. t1.docstatus = 1 %s %s
  168. group by %s
  169. """
  170. % (
  171. query_details,
  172. conditions["trans"],
  173. conditions["trans"],
  174. conditions["addl_tables"],
  175. "%s",
  176. posting_date,
  177. "%s",
  178. "%s",
  179. cond,
  180. conditions.get("addl_tables_relational_cond", ""),
  181. conditions["group_by"],
  182. ),
  183. (filters.get("company"), year_start_date, year_end_date),
  184. as_list=1,
  185. )
  186. return data
  187. def get_mon(dt):
  188. return getdate(dt).strftime("%b")
  189. def period_wise_columns_query(filters, trans):
  190. query_details = ""
  191. pwc = []
  192. bet_dates = get_period_date_ranges(filters.get("period"), filters.get("fiscal_year"))
  193. if trans in ["Purchase Receipt", "Delivery Note", "Purchase Invoice", "Sales Invoice"]:
  194. trans_date = "posting_date"
  195. if filters.period_based_on:
  196. trans_date = filters.period_based_on
  197. else:
  198. trans_date = "transaction_date"
  199. if filters.get("period") != "Yearly":
  200. for dt in bet_dates:
  201. get_period_wise_columns(dt, filters.get("period"), pwc)
  202. query_details = get_period_wise_query(dt, trans_date, query_details)
  203. else:
  204. pwc = [
  205. _(filters.get("fiscal_year")) + " (" + _("Qty") + "):Float:120",
  206. _(filters.get("fiscal_year")) + " (" + _("Amt") + "):Currency:120",
  207. ]
  208. query_details = " SUM(t2.stock_qty), SUM(t2.base_net_amount),"
  209. query_details += "SUM(t2.stock_qty), SUM(t2.base_net_amount)"
  210. return pwc, query_details
  211. def get_period_wise_columns(bet_dates, period, pwc):
  212. if period == "Monthly":
  213. pwc += [
  214. _(get_mon(bet_dates[0])) + " (" + _("Qty") + "):Float:120",
  215. _(get_mon(bet_dates[0])) + " (" + _("Amt") + "):Currency:120",
  216. ]
  217. else:
  218. pwc += [
  219. _(get_mon(bet_dates[0])) + "-" + _(get_mon(bet_dates[1])) + " (" + _("Qty") + "):Float:120",
  220. _(get_mon(bet_dates[0])) + "-" + _(get_mon(bet_dates[1])) + " (" + _("Amt") + "):Currency:120",
  221. ]
  222. def get_period_wise_query(bet_dates, trans_date, query_details):
  223. query_details += """SUM(IF(t1.%(trans_date)s BETWEEN '%(sd)s' AND '%(ed)s', t2.stock_qty, NULL)),
  224. SUM(IF(t1.%(trans_date)s BETWEEN '%(sd)s' AND '%(ed)s', t2.base_net_amount, NULL)),
  225. """ % {
  226. "trans_date": trans_date,
  227. "sd": bet_dates[0],
  228. "ed": bet_dates[1],
  229. }
  230. return query_details
  231. @frappe.whitelist(allow_guest=True)
  232. def get_period_date_ranges(period, fiscal_year=None, year_start_date=None):
  233. from dateutil.relativedelta import relativedelta
  234. if not year_start_date:
  235. year_start_date, year_end_date = frappe.get_cached_value(
  236. "Fiscal Year", fiscal_year, ["year_start_date", "year_end_date"]
  237. )
  238. increment = {"Monthly": 1, "Quarterly": 3, "Half-Yearly": 6, "Yearly": 12}.get(period)
  239. period_date_ranges = []
  240. for i in range(1, 13, increment):
  241. period_end_date = getdate(year_start_date) + relativedelta(months=increment, days=-1)
  242. if period_end_date > getdate(year_end_date):
  243. period_end_date = year_end_date
  244. period_date_ranges.append([year_start_date, period_end_date])
  245. year_start_date = period_end_date + relativedelta(days=1)
  246. if period_end_date == year_end_date:
  247. break
  248. return period_date_ranges
  249. def get_period_month_ranges(period, fiscal_year):
  250. from dateutil.relativedelta import relativedelta
  251. period_month_ranges = []
  252. for start_date, end_date in get_period_date_ranges(period, fiscal_year):
  253. months_in_this_period = []
  254. while start_date <= end_date:
  255. months_in_this_period.append(start_date.strftime("%B"))
  256. start_date += relativedelta(months=1)
  257. period_month_ranges.append(months_in_this_period)
  258. return period_month_ranges
  259. def based_wise_columns_query(based_on, trans):
  260. based_on_details = {}
  261. # based_on_cols, based_on_select, based_on_group_by, addl_tables
  262. if based_on == "Item":
  263. based_on_details["based_on_cols"] = ["Item:Link/Item:120", "Item Name:Data:120"]
  264. based_on_details["based_on_select"] = "t2.item_code, t2.item_name,"
  265. based_on_details["based_on_group_by"] = "t2.item_code"
  266. based_on_details["addl_tables"] = ""
  267. elif based_on == "Item Group":
  268. based_on_details["based_on_cols"] = ["Item Group:Link/Item Group:120"]
  269. based_on_details["based_on_select"] = "t2.item_group,"
  270. based_on_details["based_on_group_by"] = "t2.item_group"
  271. based_on_details["addl_tables"] = ""
  272. elif based_on == "Customer":
  273. based_on_details["based_on_cols"] = [
  274. "Customer:Link/Customer:120",
  275. "Territory:Link/Territory:120",
  276. ]
  277. based_on_details["based_on_select"] = "t1.customer_name, t1.territory, "
  278. based_on_details["based_on_group_by"] = (
  279. "t1.party_name" if trans == "Quotation" else "t1.customer"
  280. )
  281. based_on_details["addl_tables"] = ""
  282. elif based_on == "Customer Group":
  283. based_on_details["based_on_cols"] = ["Customer Group:Link/Customer Group"]
  284. based_on_details["based_on_select"] = "t1.customer_group,"
  285. based_on_details["based_on_group_by"] = "t1.customer_group"
  286. based_on_details["addl_tables"] = ""
  287. elif based_on == "Supplier":
  288. based_on_details["based_on_cols"] = [
  289. "Supplier:Link/Supplier:120",
  290. "Supplier Group:Link/Supplier Group:140",
  291. ]
  292. based_on_details["based_on_select"] = "t1.supplier, t3.supplier_group,"
  293. based_on_details["based_on_group_by"] = "t1.supplier"
  294. based_on_details["addl_tables"] = ",`tabSupplier` t3"
  295. based_on_details["addl_tables_relational_cond"] = " and t1.supplier = t3.name"
  296. elif based_on == "Supplier Group":
  297. based_on_details["based_on_cols"] = ["Supplier Group:Link/Supplier Group:140"]
  298. based_on_details["based_on_select"] = "t3.supplier_group,"
  299. based_on_details["based_on_group_by"] = "t3.supplier_group"
  300. based_on_details["addl_tables"] = ",`tabSupplier` t3"
  301. based_on_details["addl_tables_relational_cond"] = " and t1.supplier = t3.name"
  302. elif based_on == "Territory":
  303. based_on_details["based_on_cols"] = ["Territory:Link/Territory:120"]
  304. based_on_details["based_on_select"] = "t1.territory,"
  305. based_on_details["based_on_group_by"] = "t1.territory"
  306. based_on_details["addl_tables"] = ""
  307. elif based_on == "Project":
  308. if trans in ["Sales Invoice", "Delivery Note", "Sales Order"]:
  309. based_on_details["based_on_cols"] = ["Project:Link/Project:120"]
  310. based_on_details["based_on_select"] = "t1.project,"
  311. based_on_details["based_on_group_by"] = "t1.project"
  312. based_on_details["addl_tables"] = ""
  313. elif trans in ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]:
  314. based_on_details["based_on_cols"] = ["Project:Link/Project:120"]
  315. based_on_details["based_on_select"] = "t2.project,"
  316. based_on_details["based_on_group_by"] = "t2.project"
  317. based_on_details["addl_tables"] = ""
  318. else:
  319. frappe.throw(_("Project-wise data is not available for Quotation"))
  320. return based_on_details
  321. def group_wise_column(group_by):
  322. if group_by:
  323. return [group_by + ":Link/" + group_by + ":120"]
  324. else:
  325. return []