def execute(): doctypes = [ "salary_component", "Employee Tax Exemption Declaration", "Employee Tax Exemption Proof Submission", "Employee Tax Exemption Declaration Category", "Employee Tax Exemption Proof Submission Detail", "gratuity_rule", "gratuity_rule_slab", "gratuity_applicable_component", ] for doctype in doctypes: frappe.reload_doc("Payroll", "doctype", doctype, force=True) reports = [ "Professional Tax Deductions", "Provident Fund Deductions", "E-Invoice Summary" ] for report in reports: frappe.reload_doc("Regional", "Report", report) frappe.reload_doc("Regional", "Report", report) if erpnext.get_region() == "India": create_custom_field( "Salary Component", dict( fieldname="component_type", label="Component Type", fieldtype="Select", insert_after="description", options= "\nProvident Fund\nAdditional Provident Fund\nProvident Fund Loan\nProfessional Tax", depends_on='eval:doc.type == "Deduction"', ), ) if frappe.db.exists("Salary Component", "Income Tax"): frappe.db.set_value("Salary Component", "Income Tax", "is_income_tax_component", 1) if frappe.db.exists("Salary Component", "TDS"): frappe.db.set_value("Salary Component", "TDS", "is_income_tax_component", 1) components = frappe.db.sql( "select name from `tabSalary Component` where variable_based_on_taxable_salary = 1", as_dict=1) for component in components: frappe.db.set_value("Salary Component", component.name, "is_income_tax_component", 1) if erpnext.get_region() == "India": if frappe.db.exists("Salary Component", "Provident Fund"): frappe.db.set_value("Salary Component", "Provident Fund", "component_type", "Provident Fund") if frappe.db.exists("Salary Component", "Professional Tax"): frappe.db.set_value("Salary Component", "Professional Tax", "component_type", "Professional Tax")
def get_data(filters): data = [] fields = ["employee", "branch", "bank_name", "bank_ac_no", "salary_mode"] if erpnext.get_region() == "India": fields += ["ifsc_code", "micr_code"] employee_details = frappe.get_list("Employee", fields=fields) employee_data_dict = {} for d in employee_details: employee_data_dict.setdefault( d.employee, { "bank_ac_no": d.bank_ac_no, "ifsc_code": d.ifsc_code or None, "micr_code": d.micr_code or None, "branch": d.branch, "salary_mode": d.salary_mode, "bank_name": d.bank_name }) conditions = get_conditions(filters) entry = frappe.db.sql(""" select employee, employee_name, gross_pay from `tabSalary Slip` where docstatus = 1 %s """ % (conditions), as_dict=1) for d in entry: employee = { "branch": employee_data_dict.get(d.employee).get("branch"), "employee_name": d.employee_name, "employee": d.employee, "gross_pay": d.gross_pay, } if employee_data_dict.get(d.employee).get("salary_mode") == "Bank": employee["bank"] = employee_data_dict.get( d.employee).get("bank_name") employee["account_no"] = employee_data_dict.get( d.employee).get("bank_ac_no") if erpnext.get_region() == "India": employee["ifsc"] = employee_data_dict.get( d.employee).get("ifsc_code") employee["micr"] = employee_data_dict.get( d.employee).get("micr_code") else: employee["account_no"] = employee_data_dict.get( d.employee).get("salary_mode") if filters.get("type") and employee_data_dict.get( d.employee).get("salary_mode") == filters.get("type"): data.append(employee) elif not filters.get("type"): data.append(employee) return data
def get_data(filters): data = [] if erpnext.get_region() == "India": employee_pan_dict = frappe._dict( frappe.db.sql(""" select employee, pan_number from `tabEmployee`""") ) component_types = frappe.db.sql( """ select name from `tabSalary Component` where is_income_tax_component = 1 """ ) component_types = [comp_type[0] for comp_type in component_types] if not len(component_types): return [] conditions = get_conditions(filters) entry = frappe.db.sql( """ select sal.employee, sal.employee_name, sal.posting_date, ded.salary_component, ded.amount,sal.gross_pay from `tabSalary Slip` sal, `tabSalary Detail` ded where sal.name = ded.parent and ded.parentfield = 'deductions' and ded.parenttype = 'Salary Slip' and sal.docstatus = 1 %s and ded.salary_component in (%s) """ % (conditions, ", ".join(["%s"] * len(component_types))), tuple(component_types), as_dict=1, ) for d in entry: employee = { "employee": d.employee, "employee_name": d.employee_name, "it_comp": d.salary_component, "posting_date": d.posting_date, # "pan_number": employee_pan_dict.get(d.employee), "it_amount": d.amount, "gross_pay": d.gross_pay, } if erpnext.get_region() == "India": employee["pan_number"] = employee_pan_dict.get(d.employee) data.append(employee) return data
def get_columns(filters): columns = [ { "label": _("Branch"), "options": "Branch", "fieldname": "branch", "fieldtype": "Link", "width": 200, }, { "label": _("Employee Name"), "options": "Employee", "fieldname": "employee_name", "fieldtype": "Link", "width": 160, }, { "label": _("Employee"), "options": "Employee", "fieldname": "employee", "fieldtype": "Link", "width": 140, }, { "label": _("Gross Pay"), "fieldname": "gross_pay", "fieldtype": "Currency", "options": "currency", "width": 140, }, { "label": _("Bank"), "fieldname": "bank", "fieldtype": "Data", "width": 140 }, { "label": _("Account No"), "fieldname": "account_no", "fieldtype": "Data", "width": 140 }, ] if erpnext.get_region() == "India": columns += [ { "label": _("IFSC"), "fieldname": "ifsc", "fieldtype": "Data", "width": 140 }, { "label": _("MICR"), "fieldname": "micr", "fieldtype": "Data", "width": 140 }, ] return columns
def create_qr_code(doc, method): """Create QR Code after inserting Sales Inv """ region = get_region(doc.company) if region not in ['Saudi Arabia']: return # if QR Code field not present, do nothing if not hasattr(doc, 'qr_code'): return # Don't create QR Code if it already exists qr_code = doc.get("qr_code") if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): return meta = frappe.get_meta('Sales Invoice') for field in meta.get_image_fields(): if field.fieldname == 'qr_code': # Creating public url to print format default_print_format = frappe.db.get_value( 'Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value") # System Language language = frappe.get_system_settings('language') # creating qr code for the url url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?format={ default_print_format or 'Standard' }&_lang={ language }&key={ doc.get_signature() }" qr_image = io.BytesIO() url = qr_create(url, error='L') url.png(qr_image, scale=2, quiet_zone=1) # making file filename = f"QR-CODE-{doc.name}.png".replace(os.path.sep, "__") _file = frappe.get_doc({ "doctype": "File", "file_name": filename, "is_private": 0, "content": qr_image.getvalue(), "attached_to_doctype": doc.get("doctype"), "attached_to_name": doc.get("name"), "attached_to_field": "qr_code" }) _file.save() # assigning to document doc.db_set('qr_code', _file.file_url) doc.notify_update() break
def get_columns(filters): columns = [ { "label": _("Employee"), "options": "Employee", "fieldname": "employee", "fieldtype": "Link", "width": 200 }, { "label": _("Employee Name"), "options": "Employee", "fieldname": "employee_name", "fieldtype": "Link", "width": 160 }] if erpnext.get_region() == "India": columns.append({ "label": _("PAN Number"), "fieldname": "pan_number", "fieldtype": "Data", "width": 140 }) columns += [{ "label": _("Income Tax Component"), "fieldname": "it_comp", "fieldtype": "Data", "width": 170 }, { "label": _("Income Tax Amount"), "fieldname": "it_amount", "fieldtype": "Currency", "options": "currency", "width": 140 }, { "label": _("Gross Pay"), "fieldname": "gross_pay", "fieldtype": "Currency", "options": "currency", "width": 140 }, { "label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 140 } ] return columns
def delete_qr_code_file(doc, method=None): region = get_region(doc.company) if region not in ["Saudi Arabia"]: return if hasattr(doc, "ksa_einv_qr"): if doc.get("ksa_einv_qr"): file_doc = frappe.get_list("File", {"file_url": doc.get("ksa_einv_qr")}) if len(file_doc): frappe.delete_doc("File", file_doc[0].name)
def execute(): doctypes = [ 'salary_component', 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission', 'Employee Tax Exemption Declaration Category', 'Employee Tax Exemption Proof Submission Detail' ] for doctype in doctypes: frappe.reload_doc('Payroll', 'doctype', doctype) reports = ['Professional Tax Deductions', 'Provident Fund Deductions'] for report in reports: frappe.reload_doc('Regional', 'Report', report) frappe.reload_doc('Regional', 'Report', report) if erpnext.get_region() == "India": setup(patch=True) if frappe.db.exists("Salary Component", "Income Tax"): frappe.db.set_value("Salary Component", "Income Tax", "is_income_tax_component", 1) if frappe.db.exists("Salary Component", "TDS"): frappe.db.set_value("Salary Component", "TDS", "is_income_tax_component", 1) components = frappe.db.sql( "select name from `tabSalary Component` where variable_based_on_taxable_salary = 1", as_dict=1) for component in components: frappe.db.set_value("Salary Component", component.name, "is_income_tax_component", 1) if erpnext.get_region() == "India": if frappe.db.exists("Salary Component", "Provident Fund"): frappe.db.set_value("Salary Component", "Provident Fund", "component_type", "Provident Fund") if frappe.db.exists("Salary Component", "Professional Tax"): frappe.db.set_value("Salary Component", "Professional Tax", "component_type", "Professional Tax")
def delete_qr_code_file(doc, method): """Delete QR Code on deleted sales invoice""" region = get_region(doc.company) if region not in ['Saudi Arabia']: return if hasattr(doc, 'qr_code'): if doc.get('qr_code'): file_doc = frappe.get_list('File', {'file_url': doc.get('qr_code')}) if len(file_doc): frappe.delete_doc('File', file_doc[0].name)
def create_transaction_log(doc, method): region = get_region() if region not in ["France"]: return else: data = str(doc.as_dict()) frappe.get_doc({ "doctype": "Transaction Log", "reference_doctype": doc.doctype, "document_name": doc.name, "data": data }).insert(ignore_permissions=True)
def set_sales_tax(doc, method): if not TAXJAR_CALCULATE_TAX: return if get_region(doc.company) != 'United States': return if not doc.items: return if check_sales_tax_exemption(doc): return tax_dict = get_tax_data(doc) if not tax_dict: # Remove existing tax rows if address is changed from a taxable state/country setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD]) return # check if delivering within a nexus check_for_nexus(doc, tax_dict) tax_data = validate_tax_request(tax_dict) if tax_data is not None: if not tax_data.amount_to_collect: setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD]) elif tax_data.amount_to_collect > 0: # Loop through tax rows for existing Sales Tax entry # If none are found, add a row with the tax amount for tax in doc.taxes: if tax.account_head == TAX_ACCOUNT_HEAD: tax.tax_amount = tax_data.amount_to_collect doc.run_method("calculate_taxes_and_totals") break else: doc.append("taxes", { "charge_type": "Actual", "description": "Sales Tax", "account_head": TAX_ACCOUNT_HEAD, "tax_amount": tax_data.amount_to_collect }) # Assigning values to tax_collectable and taxable_amount fields in sales item table for item in tax_data.breakdown.line_items: doc.get('items')[cint(item.id)-1].tax_collectable = item.tax_collectable doc.get('items')[cint(item.id)-1].taxable_amount = item.taxable_amount doc.run_method("calculate_taxes_and_totals")
def create_transaction_log(doc, method): """ Appends the transaction to a chain of hashed logs for legal resons. Called on submit of Sales Invoice and Payment Entry. """ region = get_region() if region not in ["France", "Germany"]: return data = str(doc.as_dict()) frappe.get_doc({ "doctype": "Transaction Log", "reference_doctype": doc.doctype, "document_name": doc.name, "data": data }).insert(ignore_permissions=True)
def check_deletion_permission(doc, method): region = get_region(doc.company) if region in ["Nepal", "France"] and doc.docstatus != 0: frappe.throw( _("Deletion is not permitted for country {0}").format(region))
def check_deletion_permission(doc, method): region = get_region() if region in ["Nepal", "France"] and doc.docstatus != 0: frappe.throw(_("Deletion is not permitted for country {0}".format(region)))
def create_qr_code(doc, method=None): region = get_region(doc.company) if region not in ["Saudi Arabia"]: return # if QR Code field not present, create it. Invoices without QR are invalid as per law. if not hasattr(doc, "ksa_einv_qr"): create_custom_fields({ doc.doctype: [ dict( fieldname="ksa_einv_qr", label="KSA E-Invoicing QR", fieldtype="Attach Image", read_only=1, no_copy=1, hidden=1, ) ] }) # Don't create QR Code if it already exists qr_code = doc.get("ksa_einv_qr") if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): return meta = frappe.get_meta(doc.doctype) if "ksa_einv_qr" in [d.fieldname for d in meta.get_image_fields()]: """TLV conversion for 1. Seller's Name 2. VAT Number 3. Time Stamp 4. Invoice Amount 5. VAT Amount """ tlv_array = [] # Sellers Name seller_name = frappe.db.get_value("Company", doc.company, "company_name_in_arabic") if not seller_name: frappe.throw( _("Arabic name missing for {} in the company document").format( doc.company)) tag = bytes([1]).hex() length = bytes([len(seller_name.encode("utf-8"))]).hex() value = seller_name.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # VAT Number tax_id = frappe.db.get_value("Company", doc.company, "tax_id") if not tax_id: frappe.throw( _("Tax ID missing for {} in the company document").format( doc.company)) tag = bytes([2]).hex() length = bytes([len(tax_id)]).hex() value = tax_id.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # Time Stamp posting_date = getdate(doc.posting_date) time = get_time(doc.posting_time) seconds = time.hour * 60 * 60 + time.minute * 60 + time.second time_stamp = add_to_date(posting_date, seconds=seconds) time_stamp = time_stamp.strftime("%Y-%m-%dT%H:%M:%SZ") tag = bytes([3]).hex() length = bytes([len(time_stamp)]).hex() value = time_stamp.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # Invoice Amount invoice_amount = str(doc.grand_total) tag = bytes([4]).hex() length = bytes([len(invoice_amount)]).hex() value = invoice_amount.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # VAT Amount vat_amount = str(get_vat_amount(doc)) tag = bytes([5]).hex() length = bytes([len(vat_amount)]).hex() value = vat_amount.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # Joining bytes into one tlv_buff = "".join(tlv_array) # base64 conversion for QR Code base64_string = b64encode(bytes.fromhex(tlv_buff)).decode() qr_image = io.BytesIO() url = qr_create(base64_string, error="L") url.png(qr_image, scale=2, quiet_zone=1) name = frappe.generate_hash(doc.name, 5) # making file filename = f"QRCode-{name}.png".replace(os.path.sep, "__") _file = frappe.get_doc({ "doctype": "File", "file_name": filename, "is_private": 0, "content": qr_image.getvalue(), "attached_to_doctype": doc.get("doctype"), "attached_to_name": doc.get("name"), "attached_to_field": "ksa_einv_qr", }) _file.save() # assigning to document doc.db_set("ksa_einv_qr", _file.file_url) doc.notify_update()
def check_deletion_permission(doc, method): region = get_region() if region in ["Nepal", "France"]: frappe.throw( _("Deletion is not permitted for country {0}".format(region)))