diff --git a/base_accounting_kit/__init__.py b/base_accounting_kit/__init__.py index ff9199e83..0254d17ed 100644 --- a/base_accounting_kit/__init__.py +++ b/base_accounting_kit/__init__.py @@ -19,6 +19,7 @@ # If not, see . # ############################################################################# +from . import controllers from . import models from . import report from . import wizard diff --git a/base_accounting_kit/__manifest__.py b/base_accounting_kit/__manifest__.py index 8e77d8858..09047902d 100644 --- a/base_accounting_kit/__manifest__.py +++ b/base_accounting_kit/__manifest__.py @@ -21,7 +21,7 @@ ############################################################################# { 'name': 'Odoo 18 Full Accounting Kit for Community', - 'version': '18.0.4.0.6', + 'version': '18.0.5.0.6', 'category': 'Accounting', 'live_test_url': 'https://kit.easyinstance.com/web/login?redirect=/odoo/accounting', 'summary': """Odoo 18 Accounting, Odoo 18 Accounting Reports, Odoo18 Accounting, Odoo Accounting, Odoo18 Financial Reports, Odoo18 Asset, Odoo18 Profit and Loss, PDC, Followups, Odoo18, Accounting, Odoo Apps, Reports""", @@ -53,6 +53,7 @@ 'views/account_followup.xml', 'views/followup_line_views.xml', 'views/followup_report.xml', + 'views/res_partner_views.xml', 'wizard/asset_depreciation_confirmation_views.xml', 'wizard/asset_modify_views.xml', 'views/account_asset_asset_views.xml', @@ -88,6 +89,8 @@ 'report/report.xml', 'report/multiple_invoice_layouts.xml', 'report/multiple_invoice_report_template.xml', + 'report/res_partner_reports.xml', + 'report/res_partner_templates.xml', 'views/account_recurring_payments_view.xml', 'views/account_move_line_views.xml', 'views/account_bank_statement_views.xml', @@ -107,6 +110,7 @@ 'base_accounting_kit/static/src/js/KanbanController.js', 'base_accounting_kit/static/src/js/ListController.js', 'base_accounting_kit/static/src/js/bank_reconcile_form_lines_widget.js', + 'base_accounting_kit/static/src/js/action_manager.js', 'base_accounting_kit/static/src/xml/bank_rec_widget.xml', 'base_accounting_kit/static/src/xml/bank_reconcile_widget.xml', ] diff --git a/base_accounting_kit/controllers/__init__.py b/base_accounting_kit/controllers/__init__.py new file mode 100644 index 000000000..e9ae46223 --- /dev/null +++ b/base_accounting_kit/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Aysha Shalin (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC +# LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import statement_report diff --git a/base_accounting_kit/controllers/statement_report.py b/base_accounting_kit/controllers/statement_report.py new file mode 100644 index 000000000..06798a81d --- /dev/null +++ b/base_accounting_kit/controllers/statement_report.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Aysha Shalin (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC +# LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +import json +from odoo import http +from odoo.http import content_disposition, request +from odoo.tools import html_escape + + +class XLSXReportController(http.Controller): + """ Controller for xlsx report """ + @http.route('/xlsx_report', type='http', auth='user', methods=['POST'], + csrf=False) + def get_report_xlsx(self, model, options, output_format, report_name): + """ Get xlsx report data """ + report_obj = request.env[model].sudo() + print("oo") + options = json.loads(options) + try: + if output_format == 'xlsx': + response = request.make_response( + None, headers=[ + ('Content-Type', 'application/vnd.ms-excel'), + ('Content-Disposition', content_disposition( + report_name + '.xlsx'))]) + report_obj.get_xlsx_report(options, response) + response.set_cookie('fileToken', 'dummy token') + return response + except Exception as event: + serialize = http.serialize_exception(event) + error = { + 'code': 200, + 'message': 'Odoo Server Error', + 'data': serialize + } + return request.make_response(html_escape(json.dumps(error))) diff --git a/base_accounting_kit/doc/RELEASE_NOTES.md b/base_accounting_kit/doc/RELEASE_NOTES.md index c266eec37..253fe9ee7 100644 --- a/base_accounting_kit/doc/RELEASE_NOTES.md +++ b/base_accounting_kit/doc/RELEASE_NOTES.md @@ -44,3 +44,8 @@ #### Version 18.0.4.0.6 #### FIX - Updated the generation of asset entry when the compute depreciation button click. + +#### 13.10.2025 +#### Version 18.0.5.0.6 +#### UPDT +- Added Customer Statement feature. diff --git a/base_accounting_kit/models/res_partner.py b/base_accounting_kit/models/res_partner.py index 30a0de2c9..a439b1bd0 100644 --- a/base_accounting_kit/models/res_partner.py +++ b/base_accounting_kit/models/res_partner.py @@ -21,8 +21,12 @@ ############################################################################# from datetime import date, timedelta from odoo import api, fields, models, _ -from odoo.exceptions import UserError - +import base64 +import io +import json +import xlsxwriter +from odoo.exceptions import ValidationError, UserError +from odoo.tools.json import json_default class ResPartner(models.Model): """Inheriting res.partner""" @@ -64,6 +68,22 @@ class ResPartner(models.Model): enable_credit_limit = fields.Boolean(string="Credit Limit Enabled", compute="_compute_enable_credit_limit") + # customer statement + + customer_report_ids = fields.Many2many( + 'account.move', + compute='_compute_customer_report_ids', + help='Partner Invoices related to Customer') + vendor_statement_ids = fields.Many2many( + 'account.move', + compute='_compute_vendor_statement_ids', + help='Partner Bills related to Vendor') + currency_id = fields.Many2one( + 'res.currency', + default=lambda self: self.env.company.currency_id.id, + help="currency related to Customer or Vendor") + + def _compute_for_followup(self): """ Compute the fields 'total_due', 'total_overdue' , 'next_reminder_date' and 'followup_status' @@ -159,3 +179,349 @@ class ResPartner(models.Model): if self.blocking_stage > 0: raise UserError(_( "Warning amount should be less than Blocking amount")) + + # customer statement + def _compute_customer_report_ids(self): + """ For computing 'invoices' of partner """ + for rec in self: + inv_ids = self.env['account.move'].search( + [('partner_id', '=', rec.id), + ('move_type', '=', 'out_invoice'), + ('payment_state', '!=', 'paid'), + ('state', '=', 'posted')]) + rec.customer_report_ids = inv_ids + + def _compute_vendor_statement_ids(self): + """ For computing 'bills' of partner """ + for rec in self: + bills = self.env['account.move'].search( + [('partner_id', '=', rec.id), + ('move_type', '=', 'in_invoice'), + ('payment_state', '!=', 'paid'), + ('state', '=', 'posted')]) + rec.vendor_statement_ids = bills + + def main_query(self): + """ Return select query """ + query = """SELECT name , invoice_date, invoice_date_due, + amount_total_signed AS sub_total, + amount_residual_signed AS amount_due , + amount_residual AS balance + FROM account_move WHERE payment_state != 'paid' + AND state ='posted' AND partner_id= '%s' + AND company_id = '%s' """ % (self.id, self.env.company.id) + return query + + def amount_query(self): + """ Return query for calculating total amount """ + amount_query = """ SELECT SUM(amount_total_signed) AS total, + SUM(amount_residual) AS balance + FROM account_move WHERE payment_state != 'paid' + AND state ='posted' AND partner_id= '%s' + AND company_id = '%s' """ % (self.id, self.env.company.id) + return amount_query + + def action_share_pdf(self): + """ Action for sharing customer pdf report """ + if self.customer_report_ids: + main_query = self.main_query() + main_query += """ AND move_type IN ('out_invoice')""" + amount = self.amount_query() + amount += """ AND move_type IN ('out_invoice')""" + self.env.cr.execute(main_query) + main = self.env.cr.dictfetchall() + self.env.cr.execute(amount) + amount = self.env.cr.dictfetchall() + data = { + 'customer': self.display_name, + 'street': self.street, + 'street2': self.street2, + 'city': self.city, + 'state': self.state_id.name, + 'zip': self.zip, + 'my_data': main, + 'total': amount[0]['total'], + 'balance': amount[0]['balance'], + 'currency': self.currency_id.symbol, + } + report = self.env['ir.actions.report'].sudo()._render_qweb_pdf( + 'base_accounting_kit.res_partner_action', self, data=data) + data_record = base64.b64encode(report[0]) + ir_values = { + 'name': 'Statement Report', + 'type': 'binary', + 'datas': data_record, + 'mimetype': 'application/pdf', + 'res_model': 'res.partner' + } + attachment = self.env['ir.attachment'].sudo().create(ir_values) + email_values = { + 'email_to': self.email, + 'subject': 'Payment Statement Report', + 'body_html': '

Dear Mr/Miss. ' + self.name + + '

We have attached your ' + 'payment statement. Please check

' + '

Best regards,

' + self.env.user.name, + 'attachment_ids': [attachment.id], + } + mail = self.env['mail.mail'].sudo().create(email_values) + mail.send() + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'message': 'Email Sent Successfully', + 'type': 'success', + 'sticky': False + } + } + else: + raise ValidationError('There is no statement to send') + + def action_print_pdf(self): + """ Action for printing pdf report """ + if self.customer_report_ids: + main_query = self.main_query() + main_query += """ AND move_type IN ('out_invoice')""" + amount = self.amount_query() + amount += """ AND move_type IN ('out_invoice')""" + self.env.cr.execute(main_query) + main = self.env.cr.dictfetchall() + self.env.cr.execute(amount) + amount = self.env.cr.dictfetchall() + data = { + 'customer': self.display_name, + 'street': self.street, + 'street2': self.street2, + 'city': self.city, + 'state': self.state_id.name, + 'zip': self.zip, + 'my_data': main, + 'total': amount[0]['total'], + 'balance': amount[0]['balance'], + 'currency': self.currency_id.symbol, + } + return self.env.ref('base_accounting_kit.res_partner_action' + ).report_action(self, data=data) + else: + raise ValidationError('There is no statement to print') + + def action_print_xlsx(self): + """ Action for printing xlsx report of customers """ + if self.customer_report_ids: + main_query = self.main_query() + main_query += """ AND move_type IN ('out_invoice')""" + amount = self.amount_query() + amount += """ AND move_type IN ('out_invoice')""" + self.env.cr.execute(main_query) + main = self.env.cr.dictfetchall() + self.env.cr.execute(amount) + amount = self.env.cr.dictfetchall() + data = { + 'customer': self.display_name, + 'street': self.street, + 'street2': self.street2, + 'city': self.city, + 'state': self.state_id.name, + 'zip': self.zip, + 'my_data': main, + 'total': amount[0]['total'], + 'balance': amount[0]['balance'], + 'currency': self.currency_id.symbol, + } + return { + 'type': 'ir.actions.report', + 'data': { + 'model': 'res.partner', + 'options': json.dumps(data, + default=json_default), + 'output_format': 'xlsx', + 'report_name': 'Payment Statement Report' + }, + 'report_type': 'xlsx', + } + else: + raise ValidationError('There is no statement to print') + + def get_xlsx_report(self, data, response): + """ Get xlsx report data """ + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + cell_format_with_color = workbook.add_format({ + 'font_size': '14px', 'bold': True, + 'bg_color': 'yellow', 'border': 1}) + cell_format = workbook.add_format({'font_size': '14px', 'bold': True}) + txt = workbook.add_format({'font_size': '13px'}) + txt_border = workbook.add_format({'font_size': '13px', 'border': 1}) + head = workbook.add_format({'align': 'center', 'bold': True, + 'font_size': '22px'}) + sheet.merge_range('B2:Q4', 'Payment Statement Report', head) + if data['customer']: + sheet.merge_range('B7:D7', 'Customer/Supplier : ', cell_format) + sheet.merge_range('E7:H7', data['customer'], txt) + sheet.merge_range('B9:C9', 'Address : ', cell_format) + if data['street']: + sheet.merge_range('D9:F9', data['street'], txt) + if data['street2']: + sheet.merge_range('D10:F10', data['street2'], txt) + if data['city']: + sheet.merge_range('D11:F11', data['city'], txt) + if data['state']: + sheet.merge_range('D12:F12', data['state'], ) + if data['zip']: + sheet.merge_range('D13:F13', data['zip'], txt) + sheet.merge_range('B15:C15', 'Date', cell_format_with_color) + sheet.merge_range('D15:G15', 'Invoice/Bill Number', + cell_format_with_color) + sheet.merge_range('H15:I15', 'Due Date', cell_format_with_color) + sheet.merge_range('J15:L15', 'Invoices/Debit', cell_format_with_color) + sheet.merge_range('M15:O15', 'Amount Due', cell_format_with_color) + sheet.merge_range('P15:R15', 'Balance Due', cell_format_with_color) + row = 15 + column = 0 + for record in data['my_data']: + sub_total = data['currency'] + str(record['sub_total']) + amount_due = data['currency'] + str(record['amount_due']) + balance = data['currency'] + str(record['balance']) + total = data['currency'] + str(data['total']) + remain_balance = data['currency'] + str(data['balance']) + sheet.merge_range(row, column + 1, row, column + 2, + record['invoice_date'], txt_border) + sheet.merge_range(row, column + 3, row, column + 6, + record['name'], txt_border) + sheet.merge_range(row, column + 7, row, column + 8, + record['invoice_date_due'], txt_border) + sheet.merge_range(row, column + 9, row, column + 11, + sub_total, txt_border) + sheet.merge_range(row, column + 12, row, column + 14, + amount_due, txt_border) + sheet.merge_range(row, column + 15, row, column + 17, + balance, txt_border) + row = row + 1 + sheet.write(row + 2, column + 1, 'Total Amount: ', cell_format) + sheet.merge_range(row + 2, column + 3, row + 2, column + 4, + total, txt) + sheet.write(row + 4, column + 1, 'Balance Due: ', cell_format) + sheet.merge_range(row + 4, column + 3, row + 4, column + 4, + remain_balance, txt) + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() + + def action_share_xlsx(self): + """ Action for sharing xlsx report via email """ + if self.customer_report_ids: + main_query = self.main_query() + main_query += """ AND move_type IN ('out_invoice')""" + amount = self.amount_query() + amount += """ AND move_type IN ('out_invoice')""" + self.env.cr.execute(main_query) + main = self.env.cr.dictfetchall() + self.env.cr.execute(amount) + amount = self.env.cr.dictfetchall() + data = { + 'customer': self.display_name, + 'street': self.street, + 'street2': self.street2, + 'city': self.city, + 'state': self.state_id.name, + 'zip': self.zip, + 'my_data': main, + 'total': amount[0]['total'], + 'balance': amount[0]['balance'], + 'currency': self.currency_id.symbol, + } + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + cell_format = workbook.add_format({ + 'font_size': '14px', 'bold': True}) + txt = workbook.add_format({'font_size': '13px'}) + head = workbook.add_format( + {'align': 'center', 'bold': True, 'font_size': '22px'}) + sheet.merge_range('B2:P4', 'Payment Statement Report', head) + date_style = workbook.add_format( + {'text_wrap': True, 'align': 'center', + 'num_format': 'yyyy-mm-dd'}) + if data['customer']: + sheet.write('B7:C7', 'Customer : ', cell_format) + sheet.merge_range('D7:G7', data['customer'], txt) + sheet.write('B9:C7', 'Address : ', cell_format) + if data['street']: + sheet.merge_range('D9:F9', data['street'], txt) + if data['street2']: + sheet.merge_range('D10:F10', data['street2'], txt) + if data['city']: + sheet.merge_range('D11:F11', data['city'], txt) + if data['state']: + sheet.merge_range('D12:F12', data['state'], txt) + if data['zip']: + sheet.merge_range('D13:F13', data['zip'], txt) + sheet.write('B15', 'Date', cell_format) + sheet.write('D15', 'Invoice/Bill Number', cell_format) + sheet.write('H15', 'Due Date', cell_format) + sheet.write('J15', 'Invoices/Debit', cell_format) + sheet.write('M15', 'Amount Due', cell_format) + sheet.write('P15', 'Balance Due', cell_format) + row = 16 + column = 0 + for record in data['my_data']: + sub_total = data['currency'] + str(record['sub_total']) + amount_due = data['currency'] + str(record['amount_due']) + balance = data['currency'] + str(record['balance']) + total = data['currency'] + str(data['total']) + remain_balance = data['currency'] + str(data['balance']) + sheet.merge_range(row, column + 1, row, column + 2, + record['invoice_date'], date_style) + sheet.merge_range(row, column + 3, row, column + 5, + record['name'], txt) + sheet.merge_range(row, column + 7, row, column + 8, + record['invoice_date_due'], date_style) + sheet.merge_range(row, column + 9, row, column + 10, + sub_total, txt) + sheet.merge_range(row, column + 12, row, column + 13, + amount_due, txt) + sheet.merge_range(row, column + 15, row, column + 16, + balance, txt) + row = row + 1 + sheet.write(row + 2, column + 1, 'Total Amount : ', cell_format) + sheet.merge_range(row + 2, column + 4, row + 2, column + 5, + total, txt) + sheet.write(row + 4, column + 1, 'Balance Due : ', cell_format) + sheet.merge_range(row + 4, column + 4, row + 4, column + 5, + remain_balance, txt) + workbook.close() + output.seek(0) + xlsx = base64.b64encode(output.read()) + output.close() + ir_values = { + 'name': "Statement Report.xlsx", + 'type': 'binary', + 'datas': xlsx, + 'store_fname': xlsx, + } + attachment = self.env['ir.attachment'].sudo().create(ir_values) + email_values = { + 'email_to': self.email, + 'subject': 'Payment Statement Report', + 'body_html': '

Dear Mr/Miss. ' + self.name + + '

We have attached your' + ' payment statement. Please check

' + '

Best regards,

' + self.env.user.name, + 'attachment_ids': [attachment.id], + } + mail = self.env['mail.mail'].sudo().create(email_values) + mail.send() + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'message': 'Email Sent Successfully', + 'type': 'success', + 'sticky': False + } + } + else: + raise ValidationError('There is no statement to send') diff --git a/base_accounting_kit/report/res_partner_reports.xml b/base_accounting_kit/report/res_partner_reports.xml new file mode 100644 index 000000000..4d4e6d4ec --- /dev/null +++ b/base_accounting_kit/report/res_partner_reports.xml @@ -0,0 +1,14 @@ + + + + + Statement Report + res.partner + qweb-pdf + base_accounting_kit.res_partner_statement_report_template + base_accounting_kit.res_partner_statement_report_template + 'Statement Report- %s' %(object.name) + + report + + \ No newline at end of file diff --git a/base_accounting_kit/report/res_partner_templates.xml b/base_accounting_kit/report/res_partner_templates.xml new file mode 100644 index 000000000..334df5652 --- /dev/null +++ b/base_accounting_kit/report/res_partner_templates.xml @@ -0,0 +1,76 @@ + + + + + \ No newline at end of file diff --git a/base_accounting_kit/static/description/assets/screenshots/customer_statement.png b/base_accounting_kit/static/description/assets/screenshots/customer_statement.png new file mode 100644 index 000000000..03edfb53a Binary files /dev/null and b/base_accounting_kit/static/description/assets/screenshots/customer_statement.png differ diff --git a/base_accounting_kit/static/description/assets/screenshots/customer_statement_excel.png b/base_accounting_kit/static/description/assets/screenshots/customer_statement_excel.png new file mode 100644 index 000000000..ae7f816e6 Binary files /dev/null and b/base_accounting_kit/static/description/assets/screenshots/customer_statement_excel.png differ diff --git a/base_accounting_kit/static/description/assets/screenshots/customer_statement_pdf.png b/base_accounting_kit/static/description/assets/screenshots/customer_statement_pdf.png new file mode 100644 index 000000000..09118ce97 Binary files /dev/null and b/base_accounting_kit/static/description/assets/screenshots/customer_statement_pdf.png differ diff --git a/base_accounting_kit/static/description/index.html b/base_accounting_kit/static/description/index.html index a344bbf98..2edf592a3 100644 --- a/base_accounting_kit/static/description/index.html +++ b/base_accounting_kit/static/description/index.html @@ -287,6 +287,66 @@ + +

+
+
+ +
+ This module uses some external python dependencies : + openpyxl, ofxparse and qifparse. Before + installing the module install the python + package + first. The required python packages can be installed using the + following commands. +
+
+ pip + install openpyxl + pip + install ofxparse + pip + install qifparse +
+
+ If you are running Odoo in a Docker environment, you can safely install the qifparse package by following the steps below: +
+ 1. Create a custom Dockerfile (e.g. Dockerfile.odoo) with the following content: + FROM odoo:18.0
+ + USER root
+ + # Install qifparse to a custom directory
+ RUN pip3 install --target=/opt/qiflibs qifparse
+ + # Add that directory to PYTHONPATH
+ ENV PYTHONPATH="/opt/qiflibs:$PYTHONPATH"
+ + USER odoo
+ 2.Update your docker-compose.yml to use this custom Dockerfile for the web service: + services:
+   web:
+     build:
+       context: .
+       dockerfile: Dockerfile.odoo
+
+ 3. Rebuild and restart the containers: + docker-compose build
+ docker-compose up -d +
+
+
+
+
+ +

@@ -1417,6 +1477,102 @@

+
+
+
+
+

+ + A quick option to access Customer Statements in Contacts + + +

+
+
+

+ View and manage all customer statements directly from the contact’s form view. +

+
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+

+ + + Payment Statement Report + + +

+
+
+

+ Generate, download, and email customer statements as PDF reports with button clicks directly from the contact’s form view +

+
+ +
+
+ +
+
+
+
+ +
+
+
+
+

+ + + Payment Statement Report Excel + + +

+
+
+

+ Generate, download, and email customer statements as Excel reports with button clicks directly from the contact’s form view +

+
+ +
+
+ +
+
+
+
+
+
+
+

+ Latest Release 18.0.5.0.6 +

+ + 13th Oct, 2025 + +
+
+
+
+
+ Updt +
+
+
+
    +
  • + Added Customer Statement feature. +
  • +
+
+
+
+
+
+

diff --git a/base_accounting_kit/static/src/js/action_manager.js b/base_accounting_kit/static/src/js/action_manager.js new file mode 100644 index 000000000..1561907b8 --- /dev/null +++ b/base_accounting_kit/static/src/js/action_manager.js @@ -0,0 +1,16 @@ +/** @odoo-module*/ +import {registry} from "@web/core/registry"; +import {download} from "@web/core/network/download"; +import { BlockUI, unblockUI } from "@web/core/ui/block_ui"; +// Action manager for xlsx report +registry.category('ir.actions.report handlers').add('xlsx', async (action) => { + if (action.report_type === 'xlsx'){ + BlockUI; + await download({ + url : '/xlsx_report', + data : action.data, + error : (error) => self.call('crash_manager', 'rpc_error', error), + complete: () => unblockUI, + }); + } +}) diff --git a/base_accounting_kit/views/res_partner_views.xml b/base_accounting_kit/views/res_partner_views.xml new file mode 100644 index 000000000..4252329f4 --- /dev/null +++ b/base_accounting_kit/views/res_partner_views.xml @@ -0,0 +1,93 @@ + + + + + res.partner.view.form.inherit.base.account.report + + res.partner + + + + + + + + +
+
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
\ No newline at end of file