2019-05-03 21:21:37 +05:30
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright (c) 2018, Frappe and contributors
|
|
|
|
# For license information, please see license.txt
|
|
|
|
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import frappe
|
|
|
|
from frappe.model.document import Document
|
|
|
|
from frappe.utils import cint,cstr, today
|
|
|
|
import re
|
|
|
|
import datetime
|
|
|
|
from collections import OrderedDict
|
2019-05-05 20:45:21 +05:30
|
|
|
from frappe.core.doctype.file.file import download_file
|
2019-05-03 21:21:37 +05:30
|
|
|
|
|
|
|
def create_bank_remittance_txt(name):
|
2019-05-06 16:37:34 +05:30
|
|
|
payment_order = frappe.get_doc("Payment Order", name)
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-06 16:37:34 +05:30
|
|
|
no_of_records = len(payment_order.get("references"))
|
2019-05-08 15:57:29 +05:30
|
|
|
total_amount = sum(entry.get("amount") for entry in payment_order.get("references"))
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-08 15:57:29 +05:30
|
|
|
product_code, client_code, company_email = frappe.db.get_value("Company",
|
2019-05-06 16:26:05 +05:30
|
|
|
filters={'name' : payment_order.company},
|
2019-05-08 15:57:29 +05:30
|
|
|
fieldname=['product_code', 'client_code', 'email'])
|
2019-05-06 16:26:05 +05:30
|
|
|
|
|
|
|
header, file_name = get_header_row(payment_order, client_code)
|
|
|
|
batch = get_batch_row(payment_order, no_of_records, total_amount, product_code)
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-06 16:37:34 +05:30
|
|
|
detail = []
|
|
|
|
for ref_doc in payment_order.get("references"):
|
2019-05-08 15:57:29 +05:30
|
|
|
detail += get_detail_row(ref_doc, payment_order, company_email)
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-06 16:37:34 +05:30
|
|
|
trailer = get_trailer_row(no_of_records, total_amount)
|
|
|
|
detail_records = "\n".join(detail)
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-08 15:57:29 +05:30
|
|
|
return "\n".join([header, batch, detail_records, trailer]), file_name
|
2019-05-03 21:21:37 +05:30
|
|
|
|
|
|
|
@frappe.whitelist()
|
2019-05-05 20:45:21 +05:30
|
|
|
def generate_report(name):
|
2019-05-06 16:37:34 +05:30
|
|
|
data, file_name = create_bank_remittance_txt(name)
|
|
|
|
|
|
|
|
f = frappe.get_doc({
|
|
|
|
'doctype': 'File',
|
|
|
|
'file_name': file_name,
|
|
|
|
'content': data,
|
|
|
|
"attached_to_doctype": 'Payment Order',
|
|
|
|
"attached_to_name": name,
|
|
|
|
'is_private': True
|
|
|
|
})
|
|
|
|
f.save()
|
2019-05-08 15:57:29 +05:30
|
|
|
return {
|
|
|
|
'file_url': f.file_url,
|
|
|
|
'file_name': file_name
|
|
|
|
}
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-08 15:57:29 +05:30
|
|
|
def generate_file_name(name, company_account, date):
|
2019-05-06 16:37:34 +05:30
|
|
|
''' generate file name with format (account_code)_mmdd_(payment_order_no) '''
|
2019-05-08 15:57:29 +05:30
|
|
|
bank, acc_no = frappe.db.get_value("Bank Account", {"name": company_account}, ['bank', 'bank_account_no'])
|
|
|
|
return bank[:1]+str(acc_no)[-4:]+'_'+date.strftime("%m%d")+sanitize_data(name, '')[4:]+'.txt'
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-06 16:26:05 +05:30
|
|
|
def get_header_row(doc, client_code):
|
2019-05-06 16:37:34 +05:30
|
|
|
''' Returns header row and generated file name '''
|
2019-05-08 15:57:29 +05:30
|
|
|
file_name = generate_file_name(doc.name, doc.company_bank_account, doc.posting_date)
|
2019-05-06 16:37:34 +05:30
|
|
|
header = ["H"]
|
|
|
|
header.append(cstr(client_code)[:20])
|
|
|
|
header += [''] * 3
|
|
|
|
header.append(cstr(file_name)[:20])
|
|
|
|
return "~".join(header), file_name
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-06 16:26:05 +05:30
|
|
|
def get_batch_row(doc, no_of_records, total_amount, product_code):
|
2019-05-06 16:37:34 +05:30
|
|
|
batch = ["B"]
|
2019-05-08 15:57:29 +05:30
|
|
|
batch.append(cstr(no_of_records)[:5])
|
|
|
|
batch.append(cstr(format(total_amount, '0.2f'))[:17])
|
2019-05-06 16:37:34 +05:30
|
|
|
batch.append(sanitize_data(doc.name, '_')[:20])
|
|
|
|
batch.append(format_date(doc.posting_date))
|
|
|
|
batch.append(product_code[:20])
|
|
|
|
return "~".join(batch)
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-08 15:57:29 +05:30
|
|
|
def get_detail_row(ref_doc, payment_entry, company_email):
|
|
|
|
|
|
|
|
payment_date = format_date(payment_entry.posting_date)
|
2019-05-06 16:37:34 +05:30
|
|
|
payment_entry = frappe.get_cached_doc('Payment Entry', ref_doc.payment_entry)
|
|
|
|
supplier_bank_details = frappe.get_cached_doc('Bank Account', ref_doc.bank_account)
|
2019-05-08 15:57:29 +05:30
|
|
|
company_bank_acc_no = frappe.db.get_value("Bank Account", {'name': payment_entry.bank_account}, ['bank_account_no'])
|
|
|
|
|
2019-05-06 16:37:34 +05:30
|
|
|
addr_link = frappe.db.get_value('Dynamic Link',
|
|
|
|
{
|
|
|
|
'link_doctype': 'Supplier',
|
|
|
|
'link_name': 'Sample Supplier',
|
|
|
|
'parenttype':'Address',
|
|
|
|
'parent': ('like', '%-Billing')
|
2019-05-08 15:57:29 +05:30
|
|
|
}, 'parent')
|
|
|
|
|
2019-05-06 16:37:34 +05:30
|
|
|
supplier_billing_address = frappe.get_cached_doc('Address', addr_link)
|
2019-05-11 20:10:20 +05:30
|
|
|
email = ','.join(filter(None, [supplier_billing_address.email_id, company_email]))
|
2019-05-08 15:57:29 +05:30
|
|
|
|
2019-05-06 16:37:34 +05:30
|
|
|
detail = OrderedDict(
|
|
|
|
record_identifier='D',
|
|
|
|
payment_ref_no=sanitize_data(ref_doc.payment_entry),
|
|
|
|
payment_type=cstr(payment_entry.mode_of_payment)[:10],
|
2019-05-08 15:57:29 +05:30
|
|
|
amount=str(format(ref_doc.amount, '.2f'))[:13],
|
2019-05-06 16:37:34 +05:30
|
|
|
payment_date=payment_date,
|
|
|
|
instrument_date=payment_date,
|
|
|
|
instrument_number='',
|
2019-05-08 15:57:29 +05:30
|
|
|
dr_account_no_client=str(company_bank_acc_no)[:20],
|
2019-05-06 16:37:34 +05:30
|
|
|
dr_description='',
|
|
|
|
dr_ref_no='',
|
|
|
|
cr_ref_no='',
|
|
|
|
bank_code_indicator='M',
|
|
|
|
beneficiary_code='',
|
|
|
|
beneficiary_name=sanitize_data(payment_entry.party, ' ')[:160],
|
2019-05-08 15:57:29 +05:30
|
|
|
beneficiary_bank=sanitize_data(supplier_bank_details.bank)[:10],
|
2019-05-06 16:37:34 +05:30
|
|
|
beneficiary_branch_code=cstr(supplier_bank_details.branch_code),
|
|
|
|
beneficiary_acc_no=supplier_bank_details.bank_account_no,
|
|
|
|
location='',
|
|
|
|
print_location='',
|
2019-05-08 15:57:29 +05:30
|
|
|
beneficiary_address_1=sanitize_data(cstr(supplier_billing_address.address_line1), ' ')[:50],
|
|
|
|
beneficiary_address_2=sanitize_data(cstr(supplier_billing_address.address_line2), ' ')[:50],
|
2019-05-06 16:37:34 +05:30
|
|
|
beneficiary_address_3='',
|
|
|
|
beneficiary_address_4='',
|
|
|
|
beneficiary_address_5='',
|
2019-05-08 15:57:29 +05:30
|
|
|
beneficiary_city=supplier_billing_address.city[:20],
|
|
|
|
beneficiary_zipcode=cstr(supplier_billing_address.pincode)[:6],
|
|
|
|
beneficiary_state=supplier_billing_address.state[:20],
|
|
|
|
beneficiary_email=cstr(email)[:255],
|
|
|
|
beneficiary_mobile=cstr(supplier_billing_address.phone),
|
2019-05-06 16:37:34 +05:30
|
|
|
payment_details_1='',
|
|
|
|
payment_details_2='',
|
|
|
|
payment_details_3='',
|
|
|
|
payment_details_4='',
|
|
|
|
delivery_mode=''
|
|
|
|
)
|
|
|
|
detail_record = ["~".join(list(detail.values()))]
|
2019-05-08 15:57:29 +05:30
|
|
|
|
2019-05-06 16:37:34 +05:30
|
|
|
detail_record += get_advice_rows(payment_entry)
|
|
|
|
return detail_record
|
2019-05-05 20:45:21 +05:30
|
|
|
|
|
|
|
def get_advice_rows(payment_entry):
|
2019-05-06 16:37:34 +05:30
|
|
|
''' Returns multiple advice rows for a single detail entry '''
|
|
|
|
payment_entry_date = payment_entry.posting_date.strftime("%b%y%d%m").upper()
|
|
|
|
mode_of_payment = payment_entry.mode_of_payment
|
|
|
|
advice_rows = []
|
|
|
|
for record in payment_entry.references:
|
|
|
|
advice = ['E']
|
|
|
|
advice.append(cstr(mode_of_payment))
|
|
|
|
advice.append(cstr(record.total_amount))
|
|
|
|
advice.append('')
|
|
|
|
advice.append(cstr(record.outstanding_amount))
|
|
|
|
advice.append(record.reference_name)
|
|
|
|
advice.append(format_date(record.due_date))
|
|
|
|
advice.append(payment_entry_date)
|
|
|
|
advice_rows.append("~".join(advice))
|
|
|
|
return advice_rows
|
2019-05-03 21:21:37 +05:30
|
|
|
|
|
|
|
def get_trailer_row(no_of_records, total_amount):
|
2019-05-06 16:37:34 +05:30
|
|
|
''' Returns trailer row '''
|
|
|
|
trailer = ["T"]
|
2019-05-08 15:57:29 +05:30
|
|
|
trailer.append(cstr(no_of_records)[:5])
|
|
|
|
trailer.append(cstr(format(total_amount, '.2f'))[:17])
|
2019-05-06 16:37:34 +05:30
|
|
|
return "~".join(trailer)
|
2019-05-03 21:21:37 +05:30
|
|
|
|
2019-05-06 16:26:05 +05:30
|
|
|
def sanitize_data(val, replace_str=''):
|
2019-05-06 16:37:34 +05:30
|
|
|
''' Remove all the non-alphanumeric characters from string '''
|
|
|
|
pattern = pattern = re.compile('[\W_]+')
|
|
|
|
return pattern.sub(replace_str, val)
|
2019-05-03 21:21:37 +05:30
|
|
|
|
|
|
|
def format_date(val):
|
2019-05-06 16:37:34 +05:30
|
|
|
''' Convert a datetime object to DD/MM/YYYY format '''
|
|
|
|
return val.strftime("%d/%m/%Y")
|