blob: 85c95647225db88be4993507892443c656ef0a64 [file] [log] [blame]
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +05301# -*- coding: utf-8 -*-
2# Copyright (c) 2018, Frappe and contributors
3# For license information, please see license.txt
4
5from __future__ import unicode_literals
6import frappe
7from frappe.model.document import Document
8from frappe.utils import cint,cstr, today
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +05309from frappe import _
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053010import re
11import datetime
12from collections import OrderedDict
13
14def create_bank_remittance_txt(name):
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +053015 payment_order = frappe.get_cached_doc("Payment Order", name)
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053016
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053017 no_of_records = len(payment_order.get("references"))
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053018 total_amount = sum(entry.get("amount") for entry in payment_order.get("references"))
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053019
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053020 product_code, client_code, company_email = frappe.db.get_value("Company",
Mangesh-Khairnar66a3c992019-05-06 16:26:05 +053021 filters={'name' : payment_order.company},
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053022 fieldname=['product_code', 'client_code', 'email'])
Mangesh-Khairnar66a3c992019-05-06 16:26:05 +053023
24 header, file_name = get_header_row(payment_order, client_code)
25 batch = get_batch_row(payment_order, no_of_records, total_amount, product_code)
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053026
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053027 detail = []
28 for ref_doc in payment_order.get("references"):
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053029 detail += get_detail_row(ref_doc, payment_order, company_email)
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053030
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053031 trailer = get_trailer_row(no_of_records, total_amount)
32 detail_records = "\n".join(detail)
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053033
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053034 return "\n".join([header, batch, detail_records, trailer]), file_name
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053035
36@frappe.whitelist()
Mangesh-Khairnar08a375b2019-05-05 20:45:21 +053037def generate_report(name):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053038 data, file_name = create_bank_remittance_txt(name)
Mangesh-Khairnarc4486642019-05-05 22:36:32 +053039
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053040 f = frappe.get_doc({
41 'doctype': 'File',
42 'file_name': file_name,
43 'content': data,
44 "attached_to_doctype": 'Payment Order',
45 "attached_to_name": name,
46 'is_private': True
47 })
48 f.save()
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053049 return {
50 'file_url': f.file_url,
51 'file_name': file_name
52 }
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053053
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053054def generate_file_name(name, company_account, date):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053055 ''' generate file name with format (account_code)_mmdd_(payment_order_no) '''
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053056 bank, acc_no = frappe.db.get_value("Bank Account", {"name": company_account}, ['bank', 'bank_account_no'])
57 return bank[:1]+str(acc_no)[-4:]+'_'+date.strftime("%m%d")+sanitize_data(name, '')[4:]+'.txt'
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053058
Mangesh-Khairnar66a3c992019-05-06 16:26:05 +053059def get_header_row(doc, client_code):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053060 ''' Returns header row and generated file name '''
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053061 file_name = generate_file_name(doc.name, doc.company_bank_account, doc.posting_date)
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053062 header = ["H"]
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +053063 header.append(validate_field_size(client_code, "Client Code", 20))
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053064 header += [''] * 3
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +053065 header.append(validate_field_size(file_name, "File Name", 20))
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053066 return "~".join(header), file_name
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053067
Mangesh-Khairnar66a3c992019-05-06 16:26:05 +053068def get_batch_row(doc, no_of_records, total_amount, product_code):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053069 batch = ["B"]
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +053070 batch.append(validate_field_size(no_of_records, "No Of Records", 5))
71 batch.append(validate_amount(format(total_amount, '0.2f'), 17))
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053072 batch.append(sanitize_data(doc.name, '_')[:20])
73 batch.append(format_date(doc.posting_date))
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +053074 batch.append(validate_field_size(product_code,"Product Code", 20))
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053075 return "~".join(batch)
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +053076
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053077def get_detail_row(ref_doc, payment_entry, company_email):
78
79 payment_date = format_date(payment_entry.posting_date)
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053080 payment_entry = frappe.get_cached_doc('Payment Entry', ref_doc.payment_entry)
81 supplier_bank_details = frappe.get_cached_doc('Bank Account', ref_doc.bank_account)
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053082 company_bank_acc_no = frappe.db.get_value("Bank Account", {'name': payment_entry.bank_account}, ['bank_account_no'])
83
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053084 addr_link = frappe.db.get_value('Dynamic Link',
85 {
86 'link_doctype': 'Supplier',
87 'link_name': 'Sample Supplier',
88 'parenttype':'Address',
89 'parent': ('like', '%-Billing')
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053090 }, 'parent')
91
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053092 supplier_billing_address = frappe.get_cached_doc('Address', addr_link)
Mangesh-Khairnar4df61b12019-05-11 20:10:20 +053093 email = ','.join(filter(None, [supplier_billing_address.email_id, company_email]))
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +053094
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +053095 detail = OrderedDict(
96 record_identifier='D',
97 payment_ref_no=sanitize_data(ref_doc.payment_entry),
98 payment_type=cstr(payment_entry.mode_of_payment)[:10],
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +053099 amount=str(validate_amount(format(ref_doc.amount, '.2f'),13)),
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530100 payment_date=payment_date,
101 instrument_date=payment_date,
102 instrument_number='',
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530103 dr_account_no_client=str(validate_field_size(company_bank_acc_no, "Company Bank Account", 20)),
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530104 dr_description='',
105 dr_ref_no='',
106 cr_ref_no='',
107 bank_code_indicator='M',
108 beneficiary_code='',
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530109 beneficiary_name=sanitize_data(validate_information(payment_entry, "party", 160), ' '),
110 beneficiary_bank=sanitize_data(validate_information(supplier_bank_details, "bank", 10)),
111 beneficiary_branch_code=cstr(validate_information(supplier_bank_details, "branch_code", 11)),
112 beneficiary_acc_no=validate_information(supplier_bank_details, "bank_account_no", 20),
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530113 location='',
114 print_location='',
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530115 beneficiary_address_1=validate_field_size(sanitize_data(cstr(supplier_billing_address.address_line1), ' '), " Beneficiary Address 1", 50),
116 beneficiary_address_2=validate_field_size(sanitize_data(cstr(supplier_billing_address.address_line2), ' '), " Beneficiary Address 2", 50),
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530117 beneficiary_address_3='',
118 beneficiary_address_4='',
119 beneficiary_address_5='',
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530120 beneficiary_city=validate_field_size(cstr(supplier_billing_address.city), "Beneficiary City", 20),
121 beneficiary_zipcode=validate_field_size(cstr(supplier_billing_address.pincode), "Pin Code", 6),
122 beneficiary_state=validate_field_size(cstr(supplier_billing_address.state), "Beneficiary State", 20),
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +0530123 beneficiary_email=cstr(email)[:255],
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530124 beneficiary_mobile=validate_field_size(cstr(supplier_billing_address.phone), "Beneficiary Mobile", 10),
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530125 payment_details_1='',
126 payment_details_2='',
127 payment_details_3='',
128 payment_details_4='',
129 delivery_mode=''
130 )
131 detail_record = ["~".join(list(detail.values()))]
Mangesh-Khairnar0b2fc4f2019-05-08 15:57:29 +0530132
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530133 detail_record += get_advice_rows(payment_entry)
134 return detail_record
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +0530135
Mangesh-Khairnar08a375b2019-05-05 20:45:21 +0530136def get_advice_rows(payment_entry):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530137 ''' Returns multiple advice rows for a single detail entry '''
138 payment_entry_date = payment_entry.posting_date.strftime("%b%y%d%m").upper()
139 mode_of_payment = payment_entry.mode_of_payment
140 advice_rows = []
141 for record in payment_entry.references:
142 advice = ['E']
143 advice.append(cstr(mode_of_payment))
144 advice.append(cstr(record.total_amount))
145 advice.append('')
146 advice.append(cstr(record.outstanding_amount))
147 advice.append(record.reference_name)
148 advice.append(format_date(record.due_date))
149 advice.append(payment_entry_date)
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530150 advice_rows.append("~".join(advice))
151 return advice_rows
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +0530152
153def get_trailer_row(no_of_records, total_amount):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530154 ''' Returns trailer row '''
155 trailer = ["T"]
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530156 trailer.append(validate_field_size(no_of_records, "No of Records", 5))
157 trailer.append(validate_amount(format(total_amount, "0.2f"), 17))
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530158 return "~".join(trailer)
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +0530159
Mangesh-Khairnar66a3c992019-05-06 16:26:05 +0530160def sanitize_data(val, replace_str=''):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530161 ''' Remove all the non-alphanumeric characters from string '''
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530162 pattern = re.compile('[\W_]+')
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530163 return pattern.sub(replace_str, val)
Mangesh-Khairnarb89db7f2019-05-03 21:21:37 +0530164
165def format_date(val):
Mangesh-Khairnar27ea1712019-05-06 16:37:34 +0530166 ''' Convert a datetime object to DD/MM/YYYY format '''
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530167 return val.strftime("%d/%m/%Y")
168
169def validate_amount(val, max_int_size):
170 ''' Validate amount to be within the allowed limits '''
171 int_size = len(str(val).split('.')[0])
172
173 if int_size > max_int_size:
Mangesh-Khairnar6e358642019-05-15 15:50:50 +0530174 frappe.throw(_("Amount for a single transaction exceeds maximum allowed amount, create a separate payment order by splitting the transactions"))
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530175
176 return val
177
178def validate_information(obj, attr, max_size):
179 ''' Checks if the information is not set in the system and is within the size '''
180 if hasattr(obj, attr):
181 return validate_field_size(getattr(obj, attr), frappe.unscrub(attr), max_size)
182
183 else:
Mangesh-Khairnar6e358642019-05-15 15:50:50 +0530184 frappe.throw(_("{0} is mandatory for generating remittance payments, set the field and try again".format(frappe.unscrub(attr))))
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530185
186def validate_field_size(val, label, max_size):
187 ''' check the size of the val '''
188 if len(cstr(val)) > max_size:
Mangesh-Khairnar6e358642019-05-15 15:50:50 +0530189 frappe.throw(_("{0} field is limited to size {1}".format(label, max_size)))
Mangesh-Khairnar6175eb22019-05-14 18:25:57 +0530190 return cstr(val)