diff --git a/__init__.py b/__init__.py index 2ae6446f9dc25fe7563ce0c6a4f1cc4904124cc5..8871070722787374e6f51f62f0f636847d986285 100755 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import controllers from . import models from . import wizard diff --git a/__manifest__.py b/__manifest__.py index c99bb4adeef4e34c11ff3017dddf02a78480fc14..3c94d6b7fcf96213a024f4a877635154552a8f02 100755 --- a/__manifest__.py +++ b/__manifest__.py @@ -1,14 +1,15 @@ { "name": "CG SCOP - Cotisations CG", "summary": "CG SCOP - Cotisations CG Scop", - "version": "12.0.1.1.0", - "development_status": "Production/Stable", + "version": "12.1.1.0", "author": "Le Filament", "license": "AGPL-3", "application": False, "installable": True, "depends": [ "account", + "l10n_fr", + "lefilament_export_journal_tool", "cgscop_cotisation", ], "data": [ @@ -24,6 +25,7 @@ "views/res_config_settings.xml", "views/scop_bordereau_cg.xml", "views/scop_cotisation_cg.xml", + "wizard/export_journal_wizard_view.xml", "wizard/scop_cotisation_cg_wizard.xml", "wizard/scop_bordereau_update_confirm_view.xml", "wizard/scop_bordereau_validate_confirm_view.xml", diff --git a/controllers/__init__.py b/controllers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4170eb43ad258f212bc0d72bf089e7ec0d0fdfa3 --- /dev/null +++ b/controllers/__init__.py @@ -0,0 +1,4 @@ +# © 2021 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import main diff --git a/controllers/main.py b/controllers/main.py new file mode 100644 index 0000000000000000000000000000000000000000..823905583a8536abeddcdd5efdc64d80c2a16cd3 --- /dev/null +++ b/controllers/main.py @@ -0,0 +1,171 @@ +# Copyright 2021 Le Filament (<http://www.le-filament.com>) +# License AGPL-3 or later (http://www.gnu.org/licenses/agpl.html). + +import re +import csv +from datetime import date, datetime +from io import BytesIO, StringIO + +from odoo import http +from odoo.http import request +from odoo.addons.web.controllers.main import serialize_exception +from odoo.addons.web.controllers.main import content_disposition +from odoo.tools.misc import xlwt + + +class ExportJournalCg(http.Controller): + # ------------------------------------------------------ + # Routes + # ------------------------------------------------------ + @http.route('/web/export_journal_cg/', type='http', auth="user") + @serialize_exception + def export_journal_cg( + self, type, date_start, date_end, company_id): + """ + Sélectionne les account.move.line correspondants aux journaux + et à la plage de date définis + Crée le lignes de valeurs + :param date_start: date + :param date_end: date + :return: file + """ + # Get accounts variables + company_id = request.env['res.company'].browse(int(company_id)) + default_receivable_account_id = request.env.ref('l10n_fr.1_fr_pcg_recv') + contribution_cg_id = company_id.contribution_cg_id + contribution_ur_or_fede_journal_id = company_id.contribution_ur_or_fede_journal_id + + # Selection des dates + pas d'export du journal UR / FEDE + domain = [ + ('date', '>=', date_start), + ('date', '<=', date_end), + ('partner_id', '!=', False), + ('journal_id', '!=', contribution_ur_or_fede_journal_id.id) + ] + if type == 'empty': + domain += [('date_export', '=', False)] + + export_line_ids = request.env['account.move.line'].search(domain) + lines_to_export = [] + + for line in export_line_ids: + amount = self._move_amount(line) + direction = self._move_direction(line) + # Produit cotisation CG + Analytique + if line.product_id == contribution_cg_id: + amount_analytic = round(1/3 * amount, 2) + # Compte général + lines_to_export.append(self._export_row( + line=line, amount=amount, direction=direction, + account=('7060' + line.partner_id.ur_id.code_ur)) + ) + # Lignes analytiques + lines_to_export.append(self._export_row( + line=line, amount=amount_analytic, direction=direction, + account=('7060' + line.partner_id.ur_id.code_ur), a_type='A', + analytic='010201') + ) + lines_to_export.append(self._export_row( + line=line, amount=amount_analytic, direction=direction, + account=('7060' + line.partner_id.ur_id.code_ur), a_type='A', + analytic='020201') + ) + lines_to_export.append(self._export_row( + line=line, amount=round(amount - 2 * amount_analytic, 2), direction=direction, + account=('7060' + line.partner_id.ur_id.code_ur), a_type='A', + analytic='030201') + ) + # Compte client CG Scop + elif line.account_id == default_receivable_account_id: + # Compte général + lines_to_export.append(self._export_row( + line=line, amount=amount, direction=direction, + account=('4112' + line.partner_id.ur_id.code_ur), + adh_account=self._get_partner_number(line.partner_id)) + ) + # Banque + else: + lines_to_export.append(self._export_row( + line=line, amount=amount, direction=direction, + account=line.account_id.code) + ) + + line.write({ + 'date_export': datetime.now() + }) + + filename_ = ('Export CG Scop - ' + + date_start + + '_' + date_end) + + return self.export_cg_csv(lines_to_export, filename_) + + # ------------------------------------------------------ + # Common function + # ------------------------------------------------------ + def _export_row( + self, line, amount, direction, account=None, + adh_account=None, a_type='G', analytic=None): + # Sanitize N° Bordereau + inv_num = line.invoice_id.bordereau_id.name if line.invoice_id.bordereau_id.name else '' + # Libellé + description = line.partner_id.name.upper() + if line.name: + description += ' - ' + line.name.upper() + + return [ + line.move_id.name, # N° pièce + line.date, # Date + line.journal_id.code, # Journal + a_type, # Type d'écriture (général/analytique) + account, # Compte comptable + adh_account, # Num adh + description, # Libellé + direction, # Sens + amount, # Montant + inv_num, # N° Bordereau + line.date_maturity, # Date d'échéance + analytic, # Code analytique + ] + + def _move_direction(self, line): + if line.credit > 0.0: + return 'C' + else: + return 'D' + + def _move_amount(self, line): + if line.credit > 0: + return line.credit + else: + return line.debit + + def _get_partner_number(self, partner): + number = partner.member_number + '00' + prefix = 8 - len(number) + return (prefix * '0') + number + + def export_cg_csv(self, lines_to_export, filename_): + fp = StringIO() + export_file = csv.writer( + fp, + delimiter=';', + quoting=csv.QUOTE_ALL) + # Add header line + for line in lines_to_export: + # Format date value + line_values = [ + value if not isinstance(value, date) else value.strftime( + "%d/%m/%Y") for value in line] + export_file.writerow(line_values) + + fp.seek(0) + data = fp.read() + fp.close() + + filename = filename_ + '.csv' + csvhttpheaders = [ + ('Content-Type', 'text/csv;charset=utf8'), + ('Content-Disposition', content_disposition(filename)), + ] + return request.make_response(data, headers=csvhttpheaders) \ No newline at end of file diff --git a/wizard/__init__.py b/wizard/__init__.py index b6ea02b566051375f2cfea92ac8f821262def251..909809b470b208bb2bf6c457cdac1fea10011631 100644 --- a/wizard/__init__.py +++ b/wizard/__init__.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import account_invoice_refund +from . import export_journal_wizard from . import scop_bordereau_update_confirm from . import scop_bordereau_validate_confirm from . import scop_cotisation_cg_regul diff --git a/wizard/export_journal_wizard.py b/wizard/export_journal_wizard.py new file mode 100755 index 0000000000000000000000000000000000000000..fcca1ea2754fbe055189b101e2bfa974b21192ac --- /dev/null +++ b/wizard/export_journal_wizard.py @@ -0,0 +1,51 @@ +# Copyright 2020 Le Filament (<http://www.le-filament.com>) +# License AGPL-3 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models, fields, api, http +from odoo.exceptions import UserError + + +class ExportJournalWizard(models.TransientModel): + _name = "export.journal.cg.wizard" + _description = "Wizard export journal CG Scop" + + @api.model + def _get_default_company(self): + return self.env.user.company_id + + @api.model + def _get_default_export(self): + export = self.env['export.journal.type'].search([ + ('company_id', '=', self.env.user.company_id.id)], limit=1) + return export + + date_start = fields.Date('Date de début', required=True) + date_end = fields.Date( + string='Date de fin', + required=True, + default=fields.Date.today()) + #export_format = fields.Selection( + # [('csv', 'CSV'), ('xls', 'Excel')], + # string='Format', default="csv") + company_id = fields.Many2one( + comodel_name='res.company', + default=_get_default_company + ) + export_type = fields.Selection( + [('empty', 'Ecritures non exportées'), ('all', 'Toutes les écritures')], + string='Ecritures à exporter', default="empty") + + def get_cg_export(self): + """ + Appelle l'url de traitement et de téléchargement + :return: ir.actions.act_url + """ + return { + 'type': 'ir.actions.act_url', + 'url': + '/web/export_journal_cg?format=csv&type=%s' + % (self.export_type,) + + '&date_start=%s&date_end=%s&company_id=%d' + % (self.date_start, self.date_end, self.company_id.id), + 'target': 'new', + } diff --git a/wizard/export_journal_wizard_view.xml b/wizard/export_journal_wizard_view.xml new file mode 100755 index 0000000000000000000000000000000000000000..f49233192bab3cb470c4e70f6799b4f59e954714 --- /dev/null +++ b/wizard/export_journal_wizard_view.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<odoo> + <record id="data_export_cg_view_form" model="ir.ui.view"> + <field name="name">export.journal.cg.wizard.form</field> + <field name="model">export.journal.cg.wizard</field> + <field name="arch" type="xml"> + <form string="Export des données"> + <group> + <group> + <field name="company_id" invisible="True"/> + <field name="export_type" widget="radio" /> + </group> + </group> + + <p class="text-muted">Les dates de début et de fin sont incluses dans l'export des écritures</p> + <group> + <group> + <field name="date_start"/> + </group> + <group> + <field name="date_end"/> + </group> + </group> + <footer> + <button class="btn btn-sm btn-primary" name="get_cg_export" string="Télécharger" type="object"/> + <button class="btn btn-sm btn-default" special="cancel" string="Fermer"/> + </footer> + </form> + </field> + </record> + + <record id="data_export_cg_action" model="ir.actions.act_window"> + <field name="name">Export Journal CG Scop</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">export.journal.cg.wizard</field> + <field name="view_mode">form</field> + <field name="view_id" ref="data_export_cg_view_form"/> + <field name="target">new</field> + </record> + + <menuitem action="data_export_cg_action" id="menu_data_export_cg" name="Export Journal CG Scop" parent="account.menu_finance_entries" sequence="0" /> +</odoo>