diff --git a/erpnext/regional/print_format/irs_1099_form/__init__.py b/erpnext/regional/print_format/irs_1099_form/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/print_format/irs_1099_form/irs_1099_form.json b/erpnext/regional/print_format/irs_1099_form/irs_1099_form.json new file mode 100644 index 0000000000..1270427ad1 --- /dev/null +++ b/erpnext/regional/print_format/irs_1099_form/irs_1099_form.json @@ -0,0 +1,23 @@ +[ + { + "align_labels_right": 0, + "css": "", + "custom_format": 1, + "default_print_language": "en", + "disabled": 0, + "doc_type": "Supplier", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"
\\t\\t\\t\\t

TAX Invoice
{{ doc.name }}\\t\\t\\t\\t

\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\", \"label\": \"Customer Name\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name_in_arabic\", \"label\": \"Customer Name in Arabic\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"posting_date\", \"label\": \"Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"company_trn\", \"label\": \"Company TRN\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company_address_display\", \"label\": \"Company Address\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"200px\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_code\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\", \"label\": \"Items\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"label\": \"Total\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"charge_type\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"row_id\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"account_head\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"cost_center\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount_after_discount_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_total\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"base_tax_amount_after_discount_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"item_wise_tax_detail\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"taxes\", \"label\": \"Sales Taxes and Charges\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\", \"label\": \"Grand Total\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\", \"align\": \"left\", \"label\": \"In Words\"}]", + "html": "
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n\n \n
PAYER'S name, street address, city or town, state or province, country, ZIP
or foreign postal code, and telephone no.
\n\t{{company if company else \"\"}}
\n\t{{payer_street_address if payer_street_address else \"\"}}\n
1 RentsOMB No. 1545-0115
2018
Form 1099-MISC
Miscellaneous Income
2 Royalties
3 Other Income
\n\t{{payments if payments else \"\"}}\n\t
4 Federal Income tax withheldCopy A
For
Internal Revenue
Service Center

File with Form 1096
PAYER'S TIN
\n\t{{company_tin if company_tin else \"\"}}\n\t
RECIPIENT'S TIN

\n {{tax_id if tax_id else \"None\"}}\n
Fishing boat proceeds6 Medical and health care payments
RECIPIENT'S name
\n {{supplier if supplier else \"\"}}\n
7 Nonemployee compensation
\n\t
Substitute payments in lieu of dividends or interestFor Privacy Act
and Paperwork
Reduction Act
Notice, see the
2018 General
Instructions for
Certain
Information
Returns.
Street address (including apt. no.)
\n\t{{recipient_street_address if recipient_street_address else \"\"}}\n\t
$___________$___________
9 Payer made direct sales of
$5,000 or more of consumer products
to a buyer
(recipient) for resale
10 Crop insurance proceeds
City or town, state or province, country, and ZIP or foreign postal code
\n\t{{recipient_city_state if recipient_city_state else \"\"}}\n
$___________
1112
Account number (see instructions)FACTA filing
requirement
2nd TIN not.13 Excess golden parachute payments
$___________
14 Gross proceeds paid to an
attorney
$___________
15a Section 409A deferrals15b Section 409 income16 State tax withheld17 State/Payer's state no.18 State income
$$$$
Form 1099-MISC Cat. No. 14425J www.irs.gov/Form1099MISC Department of the Treasury - Internal Revenue Service
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {{supplier if supplier else \"\"}}\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n\n \n
PAYER'S name, street address, city or town, state or province, country, ZIP
or foreign postal code, and telephone no.
\n {{company if company else \"\"}}
\n \t{{payer_street_address if payer_street_address else \"\"}}
1 RentsOMB No. 1545-0115
2018
Form 1099-MISC
Miscellaneous Income
2 Royalties
3 Other Income
\n\t{{payments if payments else \"\"}}\n\t
4 Federal Income tax withheldCopy 1
For State Tax
Department
PAYER'S TIN
\n\t{{company_tin if company_tin else \"\"}}\n\t
RECIPIENT'S TIN
\n\t{{tax_id if tax_id else \"\"}}\n\t
Fishing boat proceeds6 Medical and health care payments
RECIPIENT'S name7 Nonemployee compensation
\n\t
Substitute payments in lieu of dividends or interest
Street address (including apt. no.)
\n\t{{recipient_street_address if recipient_street_address else \"\"}}\n\t
$___________$___________
9 Payer made direct sales of
$5,000 or more of consumer products
to a buyer
(recipient) for resale
10 Crop insurance proceeds
City or town, state or province, country, and ZIP or foreign postal code
\n\t{{recipient_city_state if recipient_city_state else \"\"}}\n\t
$___________
1112
Account number (see instructions)FACTA filing
requirement
2nd TIN not.13 Excess golden parachute payments
$___________
14 Gross proceeds paid to an
attorney
$___________
15a Section 409A deferrals15b Section 409 income16 State tax withheld17 State/Payer's state no.18 State income
$$$$
Form 1099-MISC Cat. No. 14425J www.irs.gov/Form1099MISC Department of the Treasury - Internal Revenue Service
\n
\n", + "line_breaks": 0, + "modified": "2018-10-08 14:56:56.912851", + "module": "Regional", + "name": "IRS 1099 Form", + "print_format_builder": 1, + "print_format_type": "Server", + "show_section_headings": 0, + "standard": "No" + } +] \ No newline at end of file diff --git a/erpnext/regional/report/irs_1099/__init__.py b/erpnext/regional/report/irs_1099/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/report/irs_1099/irs_1099.js b/erpnext/regional/report/irs_1099/irs_1099.js new file mode 100644 index 0000000000..2d74652cfe --- /dev/null +++ b/erpnext/regional/report/irs_1099/irs_1099.js @@ -0,0 +1,47 @@ +// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +frappe.query_reports["IRS 1099"] = { + "filters": [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1, + "width": 80, + }, + { + "fieldname":"fiscal_year", + "label": __("Fiscal Year"), + "fieldtype": "Link", + "options": "Fiscal Year", + "default": frappe.defaults.get_user_default("fiscal_year"), + "reqd": 1, + "width": 80, + }, + { + "fieldname":"supplier_group", + "label": __("Supplier Group"), + "fieldtype": "Link", + "options": "Supplier Group", + "default": "", + "reqd": 0, + "width": 80 + }, + ], + + onload: function(query_report) { + query_report.page.add_inner_button(__("Print IRS 1099 Forms"), () => { + build_1099_print(query_report); + }); + } +}; + +function build_1099_print(query_report){ + let filters = JSON.stringify(query_report.get_values()); + let w = window.open('/api/method/erpnext.regional.report.irs_1099.irs_1099.irs_1099_print?' + + '&filters=' + encodeURIComponent(filters)); + // w.print(); +} diff --git a/erpnext/regional/report/irs_1099/irs_1099.json b/erpnext/regional/report/irs_1099/irs_1099.json new file mode 100644 index 0000000000..58b63e1cd1 --- /dev/null +++ b/erpnext/regional/report/irs_1099/irs_1099.json @@ -0,0 +1,29 @@ +{ + "add_total_row": 0, + "color": "#c0392b", + "creation": "2018-09-10 00:00:00", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "icon": "fa fa-star", + "idx": 0, + "is_standard": "Yes", + "letter_head": "", + "modified": "2019-01-17 08:30:41.863572", + "modified_by": "Administrator", + "module": "Regional", + "name": "IRS 1099", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Supplier", + "report_name": "IRS 1099", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "Accounts Manager" + } + ] +} \ No newline at end of file diff --git a/erpnext/regional/report/irs_1099/irs_1099.py b/erpnext/regional/report/irs_1099/irs_1099.py new file mode 100644 index 0000000000..cef8950402 --- /dev/null +++ b/erpnext/regional/report/irs_1099/irs_1099.py @@ -0,0 +1,151 @@ +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +import json +from frappe import _, _dict +from frappe.utils import nowdate +from frappe.utils.data import fmt_money +from erpnext.accounts.utils import get_fiscal_year +from PyPDF2 import PdfFileWriter +from frappe.utils.pdf import get_pdf +from frappe.utils.print_format import read_multi_pdf +from frappe.utils.jinja import render_template + + +def execute(filters=None): + filters = filters if isinstance(filters, _dict) else _dict(filters) + if not filters: + filters.setdefault('fiscal_year', get_fiscal_year(nowdate())[0]) + filters.setdefault('company', frappe.db.get_default("company")) + data = [] + columns = get_columns() + data = frappe.db.sql(""" + SELECT + s.supplier_group as "supplier_group", + gl.party AS "supplier", + s.tax_id as "tax_id", + SUM(gl.debit) AS "payments" + FROM + `tabGL Entry` gl INNER JOIN `tabSupplier` s + WHERE + s.name = gl.party + AND s.irs_1099 = 1 + AND gl.fiscal_year = %(fiscal_year)s + AND gl.party_type = "Supplier" + + GROUP BY + gl.party + + ORDER BY + gl.party DESC""", {"fiscal_year": filters.fiscal_year, + "supplier_group": filters.supplier_group, + "company": filters.company}, as_dict=True) + return columns, data + + +def get_columns(): + return [ + { + "fieldname": "supplier_group", + "label": _("Supplier Group"), + "fieldtype": "Link", + "options": "Supplier Group", + "width": 200 + }, + { + "fieldname": "supplier", + "label": _("Supplier"), + "fieldtype": "Link", + "options": "Supplier", + "width": 200 + }, + { + "fieldname": "tax_id", + "label": _("Tax ID"), + "fieldtype": "Data", + "width": 120 + }, + { + + "fieldname": "payments", + "label": _("Total Payments"), + "fieldtype": "Currency", + "width": 120 + } + ] + + +@frappe.whitelist() +def irs_1099_print(filters): + if not filters: + frappe._dict({ + "company": frappe.db.get_default("Company"), + "fiscal_year": frappe.db.get_default("fiscal_year")}) + else: + filters = frappe._dict(json.loads(filters)) + company_address = get_payer_address_html(filters.company) + company_tin = frappe.db.get_value("Company", filters.company, "tax_id") + columns, data = execute(filters) + template = frappe.get_doc("Print Format", "IRS 1099 Form").html + output = PdfFileWriter() + for row in data: + row["company"] = filters.company + row["company_tin"] = company_tin + row["payer_street_address"] = company_address + row["recipient_street_address"], row["recipient_city_state"] = get_street_address_html("Supplier", row.supplier) + row["payments"] = fmt_money(row["payments"], precision=0, currency="USD") + frappe._dict(row) + print(row) + pdf = get_pdf(render_template(template, row), output=output if output else None) + print(pdf) + frappe.local.response.filename = filters.fiscal_year + " " + filters.company + " IRS 1099 Forms" + frappe.local.response.filecontent = read_multi_pdf(output) + frappe.local.response.type = "download" + + +def get_payer_address_html(company): + address_list = frappe.db.sql(""" + SELECT + name + FROM + tabAddress + WHERE + is_your_company_address = 1 + ORDER BY + address_type="Postal" DESC, address_type="Billing" DESC + LIMIT 1 + """, {"company": company}, as_dict=True) + if address_list: + company_address = address_list[0]["name"] + return frappe.get_doc("Address", company_address).get_display() + else: + return "" + + +def get_street_address_html(party_type, party): + address_list = frappe.db.sql(""" + SELECT + link.parent + FROM `tabDynamic Link` link, `tabAddress` address + WHERE link.parenttype = "Address" + AND link.link_name = %(party)s + ORDER BY address.address_type="Postal" DESC, + address.address_type="Billing" DESC + LIMIT 1 + """, {"party": party}, as_dict=True) + if address_list: + supplier_address = address_list[0]["parent"] + doc = frappe.get_doc("Address", supplier_address) + if doc.address_line2: + street = doc.address_line1 + "
\n" + doc.address_line2 + "
\n" + else: + street = doc.address_line1 + "
\n" + city = doc.city + ", " if doc.city else "" + city = city + doc.state + " " if doc.state else city + city = city + doc.pincode if doc.pincode else city + city += "
\n" + return street, city + else: + return "", "" diff --git a/erpnext/regional/united_states/__init__.py b/erpnext/regional/united_states/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py new file mode 100644 index 0000000000..cb82b639ba --- /dev/null +++ b/erpnext/regional/united_states/setup.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields + + +def setup(company=None, patch=True): + make_custom_fields() + add_print_formats() + update_address_template() + + +def make_custom_fields(): + custom_fields = { + 'Supplier': [ + dict(fieldname='irs_1099', fieldtype='Check', insert_after='tax_id', + label='Is IRS 1099 reporting required for supplier?') + ] + } + create_custom_fields(custom_fields) + + +def add_print_formats(): + frappe.reload_doc("regional", "print_format", "irs_1099_form") + frappe.db.sql(""" update `tabPrint Format` set disabled = 0 where + name in('IRS 1099 Form') """) + + +def update_address_template(): + html = """{{ address_line1 }}
+ {% if address_line2 %}{{ address_line2 }}
{% endif -%} + {{ city }}, {% if state %}{{ state }}{% endif -%}{% if pincode %} {{ pincode }}
{% endif -%} + {% if country != "United States" %}{{ country|upper }}{% endif -%} + """ + + address_template = frappe.db.get_value('Address Template', 'United States') + if address_template: + frappe.db.set_value('Address Template', 'United States', 'template', html) + else: + frappe.get_doc(dict(doctype='Address Template', country='United States', template=html)).insert()