diff --git a/l10n_jp_summary_invoice/README.rst b/l10n_jp_summary_invoice/README.rst new file mode 100644 index 00000000..5f65a8ee --- /dev/null +++ b/l10n_jp_summary_invoice/README.rst @@ -0,0 +1,124 @@ +===================== +Japan Summary Invoice +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:45ab1e289fb94394421ac23e39ad2cefcc03f8392e8d5037e4dfe13e5054eab0 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--japan-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-japan/tree/17.0/l10n_jp_summary_invoice + :alt: OCA/l10n-japan +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-japan-17-0/l10n-japan-17-0-l10n_jp_summary_invoice + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-japan&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a summary invoice report print functionality based on +the account_billing module. + +The printed summary invoice is intended to serve as the Qualified Tax +Invoice (適格請求書), meaning that consumption taxes should be +recalculated based on the total amount of the invoices per tax rate +included in the summary invoice. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Go to *Invoicing/Accounting > Configuration > Settings* and update the +following settings as necessary: + +- **Summary Invoice Remark**: The remark that shows in the header part + of the summary invoice, such as '下記の通り御請求申し上げます。'. +- **Show Sales Order Number**: If selected, the sales order number will + be shown for each line in the summary invoice. +- **Show Invoice Narration**: If selected, the narration will appear + for each invoice in the summary invoice report. +- **Show Invoice Total Amount**: If selected, the total amount per + invoice will appear in the summary invoice report. + +Usage +===== + +1. Create a billing for customer invoices using the functionality of the + account_billing module, and make adjustments as necessary. + + - **Remit-to Bank**: If not selected, the bank account related to + the company with the smallest sequence will show in the printed + document. + - **Due Date**: The earliest due date among the selected invoices + will be proposed. Adjust this as necessary as it will show in the + printed document. + +2. Validate the billing. An invoice for tax adjustment will be created + automatically in case the recalculated tax amount is different from + the summary of the tax amounts in the selected invoices. +3. Print the summary invoice report (合計請求書) from *Print > JP + Summary Invoice* of the billing. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Quartile + +Contributors +------------ + +- `Quartile `__: + + - Aung Ko Ko Lin + - Yoshi Tashiro + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/l10n-japan `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_jp_summary_invoice/__init__.py b/l10n_jp_summary_invoice/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/l10n_jp_summary_invoice/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/l10n_jp_summary_invoice/__manifest__.py b/l10n_jp_summary_invoice/__manifest__.py new file mode 100644 index 00000000..d2d4449c --- /dev/null +++ b/l10n_jp_summary_invoice/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2024-2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Japan Summary Invoice", + "version": "17.0.1.0.0", + "category": "Japanese Localization", + "author": "Quartile, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/l10n-japan", + "license": "AGPL-3", + "depends": ["account_billing", "report_alternative_layout"], + "data": [ + "reports/report_summary_invoice_templates.xml", + "reports/summary_invoice_reports.xml", + "views/account_billing_views.xml", + "views/account_move_views.xml", + "views/account_tax_views.xml", + "views/res_config_settings_views.xml", + ], + "development_status": "Alpha", + "installable": True, +} diff --git a/l10n_jp_summary_invoice/i18n/ja.po b/l10n_jp_summary_invoice/i18n/ja.po new file mode 100644 index 00000000..ad098ed2 --- /dev/null +++ b/l10n_jp_summary_invoice/i18n/ja.po @@ -0,0 +1,362 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_jp_summary_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-03-24 02:50+0000\n" +"PO-Revision-Date: 2025-03-24 02:50+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: l10n_jp_summary_invoice +#: model:ir.actions.report,print_report_name:l10n_jp_summary_invoice.report_jp_summary_invoice +msgid "" +"'Summary Invoice-%s%s' % (object.name, object.state == 'draft' and '-draft' " +"or '')" +msgstr "" +"'合計請求書-%s%s' % (object.name, object.state == 'draft' and '-draft' or '')" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Disc.%" +msgstr "値引%" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Amount Untaxed" +msgstr "伝票計" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Billing Date:" +msgstr "請求日:" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Payment Due:" +msgstr "お支払期日:" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Total" +msgstr "合計" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_billing +msgid "Account Billing" +msgstr "合計請求書" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_billing.py:0 +#, python-format +msgid "All invoices must be posted before validating the billing." +msgstr "すべての請求書が記帳済でなければ合計請求書は検証できません。" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_billing__threshold_date_type +msgid "" +"All invoices with date (threshold date type) before and equal to threshold " +"date will be listed in billing lines" +msgstr "閾日タイプの日付が閾日以前請求書が合計請求書明細行に追加されます。" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Amount" +msgstr "金額" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__tax_totals +msgid "Billing Totals" +msgstr "請求合計" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Cancelled Summary Invoice" +msgstr "取消済合計請求書" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_res_company +msgid "Companies" +msgstr "会社" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_res_config_settings +msgid "Config Settings" +msgstr "コンフィグ設定" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__summary_invoice_remark +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__summary_invoice_remark +msgid "Content here will be displayed in the summary invoice report." +msgstr "こちらの内容は合計請求書に表示されます。" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__date_due +msgid "Date Due" +msgstr "期日" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Description" +msgstr "説明" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Draft Summary Invoice" +msgstr "ドラフト合計請求書" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "E.g., Please find the invoice details below." +msgstr "例: 下記の通りご請求申し上げます。" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__show_invoice_narration +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_narration +msgid "" +"If enabled, the invoice narration will be displayed in the summary invoice " +"report." +msgstr "選択すると、各請求書の備考が合計請求書に表示されます" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__show_invoice_total_amount +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_total_amount +msgid "" +"If enabled, the invoice total amount will be displayed in the summary " +"invoice report." +msgstr "選択すると、各請求書の合計金額が合計請求書に表示されます" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__show_sale_order_number +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__show_sale_order_number +msgid "" +"If enabled, the sales order number will be displayed in the summary invoice " +"report lines." +msgstr "選択すると、合計請求書の明細行に販売オーダ番号が表示されます" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_billing__remit_to_bank_id +msgid "" +"If not specified, the first bank account linked to the company will show in " +"the report." +msgstr "選択がない場合は、会社に紐づく1つ目の銀行口座がレポートに表示されます" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_tax__rounding_adjustment +msgid "" +"If selected, it means that this tax was auto-generated for rounding " +"adjustment purposes." +msgstr "" +"選択されている場合、この税レコードは税額端数丸め調整のために自動生成されたも" +"のであることを示します。" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_bank_statement_line__is_not_for_billing +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_move__is_not_for_billing +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_payment__is_not_for_billing +msgid "If selected, the invoice is excluded from the billing process." +msgstr "選択した場合、請求書は合計請求書への追加対象外となります。" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_bank_statement_line__is_not_for_billing +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_move__is_not_for_billing +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_payment__is_not_for_billing +msgid "Is Not For Billing" +msgstr "合計請求書対象外" + +#. module: l10n_jp_summary_invoice +#: model:ir.actions.report,name:l10n_jp_summary_invoice.report_jp_summary_invoice +msgid "JP Summary Invoice" +msgstr "合計請求書(日本)" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_move +msgid "Journal Entry" +msgstr "仕訳" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Order No." +msgstr "オーダNo." + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__company_partner_id +msgid "Partner" +msgstr "取引先" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_move.py:0 +#, python-format +msgid "Please select invoices with the same recipient bank." +msgstr "振込先が同じ請求書を選択してください。" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Quantity" +msgstr "数量" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Reference" +msgstr "参照" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__remit_to_bank_id +msgid "Remit-to Bank" +msgstr "振込先銀行" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_tax__rounding_adjustment +msgid "Rounding Adjustment" +msgstr "丸め調整" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__show_invoice_narration +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_narration +msgid "Show Invoice Narration" +msgstr "請求書備考を表示" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__show_invoice_total_amount +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_total_amount +msgid "Show Invoice Total Amount" +msgstr "請求書合計金額を表示" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__show_sale_order_number +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__show_sale_order_number +msgid "Show Sales Order Number" +msgstr "販売オーダ番号を表示" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "Show the sales order number in the summary invoice report lines" +msgstr "合計請求書明細行に販売オーダ番号を表示" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_move_line__signed_quantity +msgid "Signed Quantity" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"Specify the header remark to be displayed on the printed summary invoice" +msgstr "合計請求書ヘッダーに表示するコメントを指定してください" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Summary Invoice" +msgstr "合計請求書" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__summary_invoice_remark +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__summary_invoice_remark +msgid "Summary Invoice Remark" +msgstr "合計請求書コメント" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "Summary Invoices" +msgstr "合計請求書" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_tax +msgid "Tax" +msgstr "税" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.view_account_billing_form_inherit +msgid "Tax Adjustment" +msgstr "消費税調整" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__tax_adjustment_entry_id +msgid "Tax Adjustment Entry" +msgstr "消費税調整仕訳" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_tax_group +msgid "Tax Group" +msgstr "税グループ" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Taxes" +msgstr "消費税" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_move_line__signed_quantity +msgid "" +"Technical field used to display the value with the correct sign in reports." +msgstr "" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_billing.py:0 +#, python-format +msgid "The invoice %s should not be included in this summary invoice." +msgstr "請求書 %s はこの合計請求書に追加できません。" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"The narration will appear for each invoice in the summary invoice report if " +"selected" +msgstr "選択すると、各請求書の備考が合計請求書に表示されます" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_billing.py:0 +#, python-format +msgid "" +"The remit-to bank of the billing is inconsistent with the one on the " +"invoices." +msgstr "合計請求書の振込先が請求書のものと異なります。" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"The total amount per invoice will appear in the summary invoice report if " +"selected" +msgstr "選択すると、各請求書の合計金額が合計請求書に表示されます" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__threshold_date_type +msgid "Threshold Date Type" +msgstr "閾日タイプ" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Unit Price" +msgstr "単価" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_move.py:0 +#, python-format +msgid "You cannot reset to draft an invoice that has been billed." +msgstr "合計請求書に追加した請求書はドラフトに戻せません。" diff --git a/l10n_jp_summary_invoice/i18n/l10n_jp_summary_invoice.pot b/l10n_jp_summary_invoice/i18n/l10n_jp_summary_invoice.pot new file mode 100644 index 00000000..26ad571e --- /dev/null +++ b/l10n_jp_summary_invoice/i18n/l10n_jp_summary_invoice.pot @@ -0,0 +1,356 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_jp_summary_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: l10n_jp_summary_invoice +#: model:ir.actions.report,print_report_name:l10n_jp_summary_invoice.report_jp_summary_invoice +msgid "" +"'Summary Invoice-%s%s' % (object.name, object.state == 'draft' and '-draft' " +"or '')" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Disc.%" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Amount Untaxed" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Billing Date:" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Payment Due:" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Total" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_billing +msgid "Account Billing" +msgstr "" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_billing.py:0 +#, python-format +msgid "All invoices must be posted before validating the billing." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_billing__threshold_date_type +msgid "" +"All invoices with date (threshold date type) before and equal to threshold " +"date will be listed in billing lines" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Amount" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__tax_totals +msgid "Billing Totals" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Cancelled Summary Invoice" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_res_company +msgid "Companies" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__summary_invoice_remark +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__summary_invoice_remark +msgid "Content here will be displayed in the summary invoice report." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__date_due +msgid "Date Due" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Description" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Draft Summary Invoice" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "E.g., Please find the invoice details below." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__show_invoice_narration +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_narration +msgid "" +"If enabled, the invoice narration will be displayed in the summary invoice " +"report." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__show_invoice_total_amount +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_total_amount +msgid "" +"If enabled, the invoice total amount will be displayed in the summary " +"invoice report." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_company__show_sale_order_number +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_res_config_settings__show_sale_order_number +msgid "" +"If enabled, the sales order number will be displayed in the summary invoice " +"report lines." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_billing__remit_to_bank_id +msgid "" +"If not specified, the first bank account linked to the company will show in " +"the report." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_tax__rounding_adjustment +msgid "" +"If selected, it means that this tax was auto-generated for rounding " +"adjustment purposes." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_bank_statement_line__is_not_for_billing +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_move__is_not_for_billing +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_payment__is_not_for_billing +msgid "If selected, the invoice is excluded from the billing process." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_bank_statement_line__is_not_for_billing +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_move__is_not_for_billing +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_payment__is_not_for_billing +msgid "Is Not For Billing" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.actions.report,name:l10n_jp_summary_invoice.report_jp_summary_invoice +msgid "JP Summary Invoice" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Order No." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__company_partner_id +msgid "Partner" +msgstr "" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_move.py:0 +#, python-format +msgid "Please select invoices with the same recipient bank." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Quantity" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Reference" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__remit_to_bank_id +msgid "Remit-to Bank" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_tax__rounding_adjustment +msgid "Rounding Adjustment" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__show_invoice_narration +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_narration +msgid "Show Invoice Narration" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__show_invoice_total_amount +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__show_invoice_total_amount +msgid "Show Invoice Total Amount" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__show_sale_order_number +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__show_sale_order_number +msgid "Show Sales Order Number" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "Show the sales order number in the summary invoice report lines" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_move_line__signed_quantity +msgid "Signed Quantity" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"Specify the header remark to be displayed on the printed summary invoice" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.report_summary_invoice_document +msgid "Summary Invoice" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_company__summary_invoice_remark +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_res_config_settings__summary_invoice_remark +msgid "Summary Invoice Remark" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "Summary Invoices" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_tax +msgid "Tax" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.view_account_billing_form_inherit +msgid "Tax Adjustment" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__tax_adjustment_entry_id +msgid "Tax Adjustment Entry" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model,name:l10n_jp_summary_invoice.model_account_tax_group +msgid "Tax Group" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Taxes" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,help:l10n_jp_summary_invoice.field_account_move_line__signed_quantity +msgid "" +"Technical field used to display the value with the correct sign in reports." +msgstr "" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_billing.py:0 +#, python-format +msgid "The invoice %s should not be included in this summary invoice." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"The narration will appear for each invoice in the summary invoice report if " +"selected" +msgstr "" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_billing.py:0 +#, python-format +msgid "" +"The remit-to bank of the billing is inconsistent with the one on the " +"invoices." +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.res_config_settings_view_form +msgid "" +"The total amount per invoice will appear in the summary invoice report if " +"selected" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model:ir.model.fields,field_description:l10n_jp_summary_invoice.field_account_billing__threshold_date_type +msgid "Threshold Date Type" +msgstr "" + +#. module: l10n_jp_summary_invoice +#: model_terms:ir.ui.view,arch_db:l10n_jp_summary_invoice.bill_line_section_layout +msgid "Unit Price" +msgstr "" + +#. module: l10n_jp_summary_invoice +#. odoo-python +#: code:addons/l10n_jp_summary_invoice/models/account_move.py:0 +#, python-format +msgid "You cannot reset to draft an invoice that has been billed." +msgstr "" diff --git a/l10n_jp_summary_invoice/models/__init__.py b/l10n_jp_summary_invoice/models/__init__.py new file mode 100644 index 00000000..30b1ac9c --- /dev/null +++ b/l10n_jp_summary_invoice/models/__init__.py @@ -0,0 +1,7 @@ +from . import account_billing +from . import account_move +from . import account_move_line +from . import account_tax_group +from . import account_tax +from . import res_company +from . import res_config_settings diff --git a/l10n_jp_summary_invoice/models/account_billing.py b/l10n_jp_summary_invoice/models/account_billing.py new file mode 100644 index 00000000..5eb63b24 --- /dev/null +++ b/l10n_jp_summary_invoice/models/account_billing.py @@ -0,0 +1,235 @@ +# Copyright 2024-2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import Command, _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountBilling(models.Model): + _inherit = "account.billing" + + # Just changing the default value + threshold_date_type = fields.Selection(default="invoice_date") + date_due = fields.Date( + compute="_compute_billing_date_due", + store=True, + readonly=False, + states={"draft": [("readonly", False)]}, + index=True, + copy=False, + ) + tax_totals = fields.Binary( + string="Billing Totals", + compute="_compute_tax_totals", + exportable=False, + ) + tax_adjustment_entry_id = fields.Many2one("account.move") + company_partner_id = fields.Many2one(related="company_id.partner_id", store=True) + remit_to_bank_id = fields.Many2one( + "res.partner.bank", + "Remit-to Bank", + domain="[('partner_id', '=', company_partner_id)]", + help="If not specified, the first bank account linked to the company will show " + "in the report.", + ) + + @api.constrains("state", "billing_line_ids") + def _check_account_move_billability(self): + for rec in self: + invoices = rec.billing_line_ids.move_id + invoice_not_for_billing = invoices.filtered( + lambda x: len(x.billing_ids.filtered(lambda x: x.state != "cancel")) > 1 + or x.is_not_for_billing + )[:1] + if invoice_not_for_billing: + raise ValidationError( + _( + "The invoice %s should not be included in this " + "summary invoice.", + invoice_not_for_billing.name, + ) + ) + + @api.constrains("remit_to_bank_id", "billing_line_ids") + def _check_remit_to_bank_consistency(self): + for rec in self: + invoices = rec.billing_line_ids.move_id + partner_bank = invoices._get_partner_bank() + if ( + rec.remit_to_bank_id + and partner_bank + and rec.remit_to_bank_id != partner_bank + ): + raise ValidationError( + _( + "The remit-to bank of the billing is inconsistent with the " + "one on the invoices.", + ) + ) + + @api.depends("billing_line_ids") + def _compute_billing_date_due(self): + for billing in self: + if not billing.billing_line_ids: + continue + billing.date_due = max( + move.invoice_date_due for move in billing.billing_line_ids.move_id + ) + + @api.depends_context("lang") + @api.depends( + "billing_line_ids", + "partner_id", + "currency_id", + ) + def _compute_tax_totals(self): + """Compute `tax_totals` by building an in-memory draft invoice that reuses all + the invoice lines referenced by the billing lines, and then delegating the tax + calculation to Odoo's standard `account.move._compute_tax_totals()`. + """ + for bill in self: + src_moves = bill.billing_line_ids.move_id + move_type = "out_invoice" + if src_moves.filtered(lambda m: m.move_type in ["in_invoice", "in_refund"]): + move_type = "in_invoice" + src_lines = src_moves.invoice_line_ids + cmd_lines = [] + for src_line in src_lines: + vals = src_line.copy_data()[0] + vals["quantity"] *= -src_line.move_id.direction_sign + cmd_lines.append(Command.create(vals)) + # Build a transient invoice holding those lines + dummy_move = self.env["account.move"].new( + { + "move_type": move_type, + "company_id": bill.company_id.id, + "currency_id": bill.currency_id.id, + "partner_id": bill.partner_id.id, + "invoice_line_ids": cmd_lines, + } + ) + dummy_move._compute_tax_totals() + bill.tax_totals = dummy_move.tax_totals + + def _update_remit_to_bank_id(self): + for rec in self: + if not rec.remit_to_bank_id: + rec.remit_to_bank_id = rec.billing_line_ids[:1].move_id.partner_bank_id + + @api.model_create_multi + def create(self, vals_list): + billings = super().create(vals_list) + billings._update_remit_to_bank_id() + return billings + + def compute_lines(self): + res = super().compute_lines() + self._update_remit_to_bank_id() + return res + + def _get_moves(self, date=False, types=False): + moves = super()._get_moves(date=date, types=types) + if self.remit_to_bank_id: + moves = moves.filtered( + lambda x: x.partner_bank_id == self.remit_to_bank_id + or not x.partner_bank_id + ) + # Prevent the billing from adding already billed invoices + moves -= moves.filtered( + lambda x: x.billing_ids.filtered(lambda x: x.state != "cancel") + or x.is_not_for_billing + ) + return moves + + def _get_tax_amount_groups_from_invoices(self): + """Get the actual tax amounts per tax based on the invoice lines + associated with billing lines. + """ + self.ensure_one() + tax_amount_groups = self.env["account.move.line"].read_group( + domain=[ + ("move_id", "in", self.billing_line_ids.move_id.ids), + "|", + ("display_type", "=", "tax"), + "&", + ("display_type", "=", "rounding"), + ("tax_repartition_line_id", "!=", False), + ], + fields=["tax_group_id", "balance"], + groupby=["tax_group_id"], + ) + return tax_amount_groups + + def _get_inv_line_account_id(self): + self.ensure_one() + return self.env["account.account"]._get_most_frequent_account_for_partner( + company_id=self.company_id.id, + partner_id=self.partner_id.id, + move_type="out_invoice", + ) + + def validate_billing(self): + res = super().validate_billing() + # Tax journal entry will be created only for customer invoice billings. + for rec in self.filtered(lambda x: x.bill_type == "out_invoice"): + tax_totals = rec.tax_totals + groups_by_subtotal = tax_totals.get("groups_by_subtotal", {}) + if not groups_by_subtotal: + continue + key = next(iter(groups_by_subtotal)) + tax_group_amount_dict = { + entry["tax_group_id"]: entry["tax_group_amount"] * -1 + for entry in groups_by_subtotal[key] + } + tax_amount_groups_invoices = rec._get_tax_amount_groups_from_invoices() + tax_group_diff_dict = {} + for tax_amount_group in tax_amount_groups_invoices: + tax_group_id = tax_amount_group["tax_group_id"][0] + tax_amount_invoices = tax_amount_group["balance"] + tax_amount_bill = tax_group_amount_dict.get(tax_group_id, 0) + tax_diff = tax_amount_invoices - tax_amount_bill + if tax_diff: + tax_group_diff_dict[tax_group_id] = tax_diff + if not tax_group_diff_dict: + continue + invoice_vals = { + "move_type": "out_invoice", + "partner_id": rec.partner_id.id, + "date": rec.date, + "invoice_date_due": rec.date_due, + "invoice_origin": rec.name, + "ref": f"Tax adjustment for {rec.name}", + "is_not_for_billing": True, + "line_ids": [], + } + inv_line_account_id = rec._get_inv_line_account_id() + diff_balance = 0.0 + for tax_group_id, diff in tax_group_diff_dict.items(): + tax_group = self.env["account.tax.group"].browse(tax_group_id) + adjustment_tax = tax_group._get_adjustment_tax() + invoice_vals["line_ids"].append( + Command.create( + { + "name": f"Tax adjustment for {tax_group.name}", + "account_id": inv_line_account_id, + "quantity": 1, + "price_unit": diff, + "tax_ids": [Command.set(adjustment_tax.ids)], + }, + ) + ) + diff_balance += diff + adjustment_move = self.env["account.move"].create(invoice_vals) + if diff_balance < 0: + adjustment_move.action_switch_invoice_into_refund_credit_note() + adjustment_move.action_post() + rec.tax_adjustment_entry_id = adjustment_move + return res + + def action_cancel(self): + res = super().action_cancel() + for rec in self: + rec.tax_adjustment_entry_id.button_draft() + rec.tax_adjustment_entry_id.button_cancel() + rec.tax_adjustment_entry_id = False + return res diff --git a/l10n_jp_summary_invoice/models/account_move.py b/l10n_jp_summary_invoice/models/account_move.py new file mode 100644 index 00000000..f4fc1fbd --- /dev/null +++ b/l10n_jp_summary_invoice/models/account_move.py @@ -0,0 +1,23 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, fields, models +from odoo.exceptions import UserError + + +class AccountMove(models.Model): + _inherit = "account.move" + + is_not_for_billing = fields.Boolean( + help="If selected, the invoice is excluded from the billing process.", + ) + + def _get_partner_bank(self): + partner_banks = self.mapped("partner_bank_id") + if len(partner_banks) > 1: + raise UserError(_("Please select invoices with the same recipient bank.")) + return partner_banks + + def action_create_billing(self): + self._get_partner_bank() + return super().action_create_billing() diff --git a/l10n_jp_summary_invoice/models/account_move_line.py b/l10n_jp_summary_invoice/models/account_move_line.py new file mode 100644 index 00000000..3b124c2c --- /dev/null +++ b/l10n_jp_summary_invoice/models/account_move_line.py @@ -0,0 +1,22 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + # We want to avoid the use of t-esc to manipulate the sign of the quantity in + # the report, as it prevents the display adjustments by report_qweb_field_option. + signed_quantity = fields.Float( + compute="_compute_signed_quantity", + digits="Product Unit of Measure", + help="Technical field used to display the value with the correct sign in " + "reports.", + ) + + def _compute_signed_quantity(self): + for line in self: + sign = -1 if line.move_type in ("out_refund", "in_refund") else 1 + line.signed_quantity = line.quantity * sign diff --git a/l10n_jp_summary_invoice/models/account_tax.py b/l10n_jp_summary_invoice/models/account_tax.py new file mode 100644 index 00000000..36eb5328 --- /dev/null +++ b/l10n_jp_summary_invoice/models/account_tax.py @@ -0,0 +1,14 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountTax(models.Model): + _inherit = "account.tax" + + rounding_adjustment = fields.Boolean( + readonly=True, + help="If selected, it means that this tax was auto-generated for rounding " + "adjustment purposes.", + ) diff --git a/l10n_jp_summary_invoice/models/account_tax_group.py b/l10n_jp_summary_invoice/models/account_tax_group.py new file mode 100644 index 00000000..b5853669 --- /dev/null +++ b/l10n_jp_summary_invoice/models/account_tax_group.py @@ -0,0 +1,31 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class AccountTaxGroup(models.Model): + _inherit = "account.tax.group" + + def _get_tax_for_group(self): + return self.env["account.tax"].search([("tax_group_id", "=", self.id)], limit=1) + + def _get_adjustment_tax(self): + self.ensure_one() + adjustment_tax = self.env["account.tax"].search( + [("rounding_adjustment", "=", True), ("tax_group_id", "=", self.id)], + limit=1, + ) + if not adjustment_tax: + origin_tax = self._get_tax_for_group() + adjustment_tax = origin_tax.copy( + { + "name": "Adjustment - %s" % self.name, + "amount_type": "division", + "amount": 100.0, + "price_include": True, + "description": "N/A", + "rounding_adjustment": True, + } + ) + return adjustment_tax diff --git a/l10n_jp_summary_invoice/models/res_company.py b/l10n_jp_summary_invoice/models/res_company.py new file mode 100644 index 00000000..061e82e8 --- /dev/null +++ b/l10n_jp_summary_invoice/models/res_company.py @@ -0,0 +1,29 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + summary_invoice_remark = fields.Html( + translate=True, + default="下記の通り御請求申し上げます。", + help="Content here will be displayed in the summary invoice report.", + ) + show_sale_order_number = fields.Boolean( + "Show Sales Order Number", + help="If enabled, the sales order number will be displayed in the summary " + "invoice report lines.", + ) + show_invoice_narration = fields.Boolean( + default=True, + help="If enabled, the invoice narration will be displayed in the summary " + "invoice report.", + ) + show_invoice_total_amount = fields.Boolean( + default=True, + help="If enabled, the invoice total amount will be displayed in the summary " + "invoice report.", + ) diff --git a/l10n_jp_summary_invoice/models/res_config_settings.py b/l10n_jp_summary_invoice/models/res_config_settings.py new file mode 100644 index 00000000..d68bc268 --- /dev/null +++ b/l10n_jp_summary_invoice/models/res_config_settings.py @@ -0,0 +1,21 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + summary_invoice_remark = fields.Html( + related="company_id.summary_invoice_remark", readonly=False + ) + show_sale_order_number = fields.Boolean( + related="company_id.show_sale_order_number", readonly=False + ) + show_invoice_narration = fields.Boolean( + related="company_id.show_invoice_narration", readonly=False + ) + show_invoice_total_amount = fields.Boolean( + related="company_id.show_invoice_total_amount", readonly=False + ) diff --git a/l10n_jp_summary_invoice/pyproject.toml b/l10n_jp_summary_invoice/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/l10n_jp_summary_invoice/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/l10n_jp_summary_invoice/readme/CONFIGURE.md b/l10n_jp_summary_invoice/readme/CONFIGURE.md new file mode 100644 index 00000000..9c56edf1 --- /dev/null +++ b/l10n_jp_summary_invoice/readme/CONFIGURE.md @@ -0,0 +1,11 @@ +Go to *Invoicing/Accounting \> Configuration \> Settings* and update the +following settings as necessary: + +- **Summary Invoice Remark**: The remark that shows in the header part + of the summary invoice, such as '下記の通り御請求申し上げます。'. +- **Show Sales Order Number**: If selected, the sales order number will + be shown for each line in the summary invoice. +- **Show Invoice Narration**: If selected, the narration will appear for + each invoice in the summary invoice report. +- **Show Invoice Total Amount**: If selected, the total amount per + invoice will appear in the summary invoice report. diff --git a/l10n_jp_summary_invoice/readme/CONTRIBUTORS.md b/l10n_jp_summary_invoice/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..2721fe7e --- /dev/null +++ b/l10n_jp_summary_invoice/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Quartile](https://www.quartile.co): + - Aung Ko Ko Lin + - Yoshi Tashiro diff --git a/l10n_jp_summary_invoice/readme/DESCRIPTION.md b/l10n_jp_summary_invoice/readme/DESCRIPTION.md new file mode 100644 index 00000000..b4168be3 --- /dev/null +++ b/l10n_jp_summary_invoice/readme/DESCRIPTION.md @@ -0,0 +1,7 @@ +This module adds a summary invoice report print functionality based on +the account_billing module. + +The printed summary invoice is intended to serve as the Qualified Tax +Invoice (適格請求書), meaning that consumption taxes should be +recalculated based on the total amount of the invoices per tax rate +included in the summary invoice. diff --git a/l10n_jp_summary_invoice/readme/USAGE.md b/l10n_jp_summary_invoice/readme/USAGE.md new file mode 100644 index 00000000..327bc014 --- /dev/null +++ b/l10n_jp_summary_invoice/readme/USAGE.md @@ -0,0 +1,13 @@ +1. Create a billing for customer invoices using the functionality of + the account_billing module, and make adjustments as necessary. + - **Remit-to Bank**: If not selected, the bank account related to + the company with the smallest sequence will show in the printed + document. + - **Due Date**: The earliest due date among the selected invoices + will be proposed. Adjust this as necessary as it will show in the + printed document. +2. Validate the billing. An invoice for tax adjustment will be created + automatically in case the recalculated tax amount is different from + the summary of the tax amounts in the selected invoices. +3. Print the summary invoice report (合計請求書) from *Print \> JP + Summary Invoice* of the billing. diff --git a/l10n_jp_summary_invoice/reports/report_summary_invoice_templates.xml b/l10n_jp_summary_invoice/reports/report_summary_invoice_templates.xml new file mode 100644 index 00000000..c8514105 --- /dev/null +++ b/l10n_jp_summary_invoice/reports/report_summary_invoice_templates.xml @@ -0,0 +1,202 @@ + + + + + diff --git a/l10n_jp_summary_invoice/reports/summary_invoice_reports.xml b/l10n_jp_summary_invoice/reports/summary_invoice_reports.xml new file mode 100644 index 00000000..d15264cf --- /dev/null +++ b/l10n_jp_summary_invoice/reports/summary_invoice_reports.xml @@ -0,0 +1,20 @@ + + + + JP Summary Invoice + account.billing + l10n_jp_summary_invoice.report_summary_invoice + qweb-pdf + l10n_jp_summary_invoice.report_summary_invoice + + report + 'Summary Invoice-%s%s' % (object.name, object.state == 'draft' and '-draft' or '') + + + + diff --git a/l10n_jp_summary_invoice/static/description/icon.png b/l10n_jp_summary_invoice/static/description/icon.png new file mode 100644 index 00000000..1dcc49c2 Binary files /dev/null and b/l10n_jp_summary_invoice/static/description/icon.png differ diff --git a/l10n_jp_summary_invoice/static/description/index.html b/l10n_jp_summary_invoice/static/description/index.html new file mode 100644 index 00000000..884aeda1 --- /dev/null +++ b/l10n_jp_summary_invoice/static/description/index.html @@ -0,0 +1,472 @@ + + + + + +Japan Summary Invoice + + + +
+

Japan Summary Invoice

+ + +

Alpha License: AGPL-3 OCA/l10n-japan Translate me on Weblate Try me on Runboat

+

This module adds a summary invoice report print functionality based on +the account_billing module.

+

The printed summary invoice is intended to serve as the Qualified Tax +Invoice (適格請求書), meaning that consumption taxes should be +recalculated based on the total amount of the invoices per tax rate +included in the summary invoice.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Configuration

+

Go to Invoicing/Accounting > Configuration > Settings and update the +following settings as necessary:

+
    +
  • Summary Invoice Remark: The remark that shows in the header part +of the summary invoice, such as ‘下記の通り御請求申し上げます。’.
  • +
  • Show Sales Order Number: If selected, the sales order number will +be shown for each line in the summary invoice.
  • +
  • Show Invoice Narration: If selected, the narration will appear +for each invoice in the summary invoice report.
  • +
  • Show Invoice Total Amount: If selected, the total amount per +invoice will appear in the summary invoice report.
  • +
+
+
+

Usage

+
    +
  1. Create a billing for customer invoices using the functionality of the +account_billing module, and make adjustments as necessary.
      +
    • Remit-to Bank: If not selected, the bank account related to +the company with the smallest sequence will show in the printed +document.
    • +
    • Due Date: The earliest due date among the selected invoices +will be proposed. Adjust this as necessary as it will show in the +printed document.
    • +
    +
  2. +
  3. Validate the billing. An invoice for tax adjustment will be created +automatically in case the recalculated tax amount is different from +the summary of the tax amounts in the selected invoices.
  4. +
  5. Print the summary invoice report (合計請求書) from Print > JP +Summary Invoice of the billing.
  6. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile
  • +
+
+
+

Contributors

+
    +
  • Quartile:
      +
    • Aung Ko Ko Lin
    • +
    • Yoshi Tashiro
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/l10n-japan project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_jp_summary_invoice/tests/__init__.py b/l10n_jp_summary_invoice/tests/__init__.py new file mode 100644 index 00000000..e1f21f24 --- /dev/null +++ b/l10n_jp_summary_invoice/tests/__init__.py @@ -0,0 +1 @@ +from . import test_l10n_jp_summary_invoice diff --git a/l10n_jp_summary_invoice/tests/test_l10n_jp_summary_invoice.py b/l10n_jp_summary_invoice/tests/test_l10n_jp_summary_invoice.py new file mode 100644 index 00000000..9a7088b5 --- /dev/null +++ b/l10n_jp_summary_invoice/tests/test_l10n_jp_summary_invoice.py @@ -0,0 +1,199 @@ +# Copyright 2024-2025 Quartile +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError +from odoo.fields import Command +from odoo.tests.common import TransactionCase + + +class TestSummaryInvoice(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.company = cls.env["res.company"].create( + { + "name": "test company", + "currency_id": cls.env.ref("base.JPY").id, + "country_id": cls.env.ref("base.jp").id, + "tax_calculation_rounding_method": "round_globally", + } + ) + cls.env.company = cls.company + account_receivable = cls.env["account.account"].create( + { + "code": "test2", + "name": "receivable", + "reconcile": True, + "account_type": "asset_receivable", + } + ) + cls.partner = cls.env["res.partner"].create( + { + "name": "Test Partner", + "property_account_receivable_id": account_receivable.id, + } + ) + cls.bank_account = cls.env["res.partner.bank"].create( + { + "partner_id": cls.env.company.partner_id.id, + "acc_number": "1234567890", + } + ) + cls.product = cls.env["product.product"].create({"name": "Test Product"}) + tax_group = cls.env["account.tax.group"].create({"name": "Tax Group"}) + cls.tax_10 = cls.env["account.tax"].create( + { + "name": "Test Tax 10%", + "amount": 10.0, + "type_tax_use": "sale", + "company_id": cls.company.id, + "tax_group_id": tax_group.id, + } + ) + cls.journal = cls.env["account.journal"].create( + {"code": "test", "name": "test", "type": "sale"} + ) + cls.account_income = cls.env["account.account"].create( + { + "code": "test1", + "name": "income", + "account_type": "income", + } + ) + + def _create_invoice(self, amount, tax, move_type="out_invoice", bank=None): + invoice = ( + self.env["account.move"] + .with_company(self.company) + .create( + { + "move_type": move_type, + "partner_id": self.partner.id, + "partner_bank_id": bank and bank.id, + "invoice_line_ids": [ + Command.create( + { + "product_id": self.product.id, + "account_id": self.account_income.id, + "quantity": 1, + "price_unit": amount, + "tax_ids": [Command.set(tax.ids)], + } + ) + ], + } + ) + ) + invoice.action_post() + return invoice + + def _get_billing_tax_amount(self, billing): + tax_totals = billing.tax_totals + groups_by_subtotal = tax_totals.get("groups_by_subtotal", {}) + key = next(iter(groups_by_subtotal)) + tax_group_amount_dict = { + entry["tax_group_id"]: entry["tax_group_amount"] * -1 + for entry in groups_by_subtotal[key] + } + return round(tax_group_amount_dict.get(self.tax_10.tax_group_id.id, 0), 0) + + def test_get_moves_filters_billed_and_flags(self): + invoice = self._create_invoice(50, self.tax_10) + invoice.write({"is_not_for_billing": True}) + billing = self.env["account.billing"].create({"partner_id": self.partner.id}) + moves = billing._get_moves() + self.assertNotIn(invoice.id, moves.ids) + + def test_constrains_invoice_not_for_billing(self): + invoice = self._create_invoice(100, self.tax_10) + invoice.write({"is_not_for_billing": True}) + with self.assertRaises(ValidationError): + self.env["account.billing"].create( + { + "partner_id": self.partner.id, + "billing_line_ids": [Command.create({"move_id": invoice.id})], + } + ) + + def test_constrains_remit_to_bank_conflict(self): + invoice = self._create_invoice(100, self.tax_10, bank=self.bank_account) + other_bank = self.env["res.partner.bank"].create( + { + "partner_id": self.env.company.partner_id.id, + "acc_number": "other_bank_acc", + } + ) + with self.assertRaises(ValidationError): + self.env["account.billing"].create( + { + "partner_id": self.partner.id, + "remit_to_bank_id": other_bank.id, + "billing_line_ids": [Command.create({"move_id": invoice.id})], + } + ) + + def test_compute_billing_due_date(self): + inv1 = self._create_invoice(100, self.tax_10) + inv2 = self._create_invoice(200, self.tax_10) + inv1.invoice_date_due = inv1.invoice_date_due.replace(day=5) + inv2.invoice_date_due = inv2.invoice_date_due.replace(day=25) + billing = self.env["account.billing"].create( + { + "partner_id": self.partner.id, + "billing_line_ids": [ + Command.create({"move_id": inv1.id}), + Command.create({"move_id": inv2.id}), + ], + } + ) + self.assertEqual(billing.date_due, inv2.invoice_date_due) + + def test_update_remit_to_bank_defaulting(self): + invoice = self._create_invoice(100, self.tax_10, bank=self.bank_account) + billing = self.env["account.billing"].create( + { + "partner_id": self.partner.id, + "billing_line_ids": [Command.create({"move_id": invoice.id})], + } + ) + self.assertEqual(billing.remit_to_bank_id, self.bank_account) + + def test_create_tax_adjustment_entry(self): + out_inv_1 = self._create_invoice(102, self.tax_10) + out_inv_2 = self._create_invoice(102, self.tax_10) + out_inv_3 = self._create_invoice(102, self.tax_10) + self.assertEqual(out_inv_1.amount_tax, 10) + self.assertEqual(out_inv_2.amount_tax, 10) + self.assertEqual(out_inv_3.amount_tax, 10) + invoices = out_inv_1 + out_inv_2 + out_inv_3 + action = invoices.action_create_billing() + billing = self.env["account.billing"].browse(action["res_id"]) + self.assertEqual(billing.state, "draft") + billing.with_company(self.company).validate_billing() + billing_tax_amount = self._get_billing_tax_amount(billing) + # The total tax amount should be 31 (306 * 0.1) + self.assertEqual(abs(billing_tax_amount), 31) + tax_adj_entry = billing.tax_adjustment_entry_id + # Since the total tax amount of the billing (31) is different from the total tax + # amount of the invoices (30), a tax adjustment entry should be created. + self.assertTrue(tax_adj_entry) + self.assertEqual(tax_adj_entry.amount_total_signed, 1) + billing.action_cancel() + self.assertTrue(tax_adj_entry.state, "cancel") + self.assertFalse(billing.tax_adjustment_entry_id) + # Add a credit note to the billing + out_ref = self._create_invoice(102, self.tax_10, "out_refund") + self.assertEqual(out_ref.amount_tax, 10) + billing.action_cancel_draft() + line_vals = { + "move_id": out_ref.id, + "amount_total": -out_ref.amount_total, + "amount_residual": -out_ref.amount_residual, + } + billing.write({"billing_line_ids": [Command.create(line_vals)]}) + self.assertIn(out_ref, billing.billing_line_ids.move_id) + billing.with_company(self.company).validate_billing() + billing_tax_amount = self._get_billing_tax_amount(billing) + # The total tax amount should be 20 (204 * 0.1) + self.assertEqual(abs(billing_tax_amount), 20) + self.assertFalse(billing.tax_adjustment_entry_id) diff --git a/l10n_jp_summary_invoice/views/account_billing_views.xml b/l10n_jp_summary_invoice/views/account_billing_views.xml new file mode 100644 index 00000000..1c1cab9b --- /dev/null +++ b/l10n_jp_summary_invoice/views/account_billing_views.xml @@ -0,0 +1,29 @@ + + + + account.billing.form.inherit + account.billing + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_jp_summary_invoice/views/account_move_views.xml b/l10n_jp_summary_invoice/views/account_move_views.xml new file mode 100644 index 00000000..647fbb04 --- /dev/null +++ b/l10n_jp_summary_invoice/views/account_move_views.xml @@ -0,0 +1,13 @@ + + + + account.move.form + account.move + + + + + + + + diff --git a/l10n_jp_summary_invoice/views/account_tax_views.xml b/l10n_jp_summary_invoice/views/account_tax_views.xml new file mode 100644 index 00000000..6e8b0c56 --- /dev/null +++ b/l10n_jp_summary_invoice/views/account_tax_views.xml @@ -0,0 +1,13 @@ + + + + account.tax.form + account.tax + + + + + + + + diff --git a/l10n_jp_summary_invoice/views/res_config_settings_views.xml b/l10n_jp_summary_invoice/views/res_config_settings_views.xml new file mode 100644 index 00000000..81d399ac --- /dev/null +++ b/l10n_jp_summary_invoice/views/res_config_settings_views.xml @@ -0,0 +1,41 @@ + + + + res.config.settings.view.form - l10n_jp_summary_invoice + res.config.settings + + + + + + + + + + + + + + + + + + + + +