From 8879b1c391af115e6025c9bd04bfb1403feacc0a Mon Sep 17 00:00:00 2001 From: EstherWee <89062424+EstherWee@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:58:01 +0700 Subject: [PATCH 01/14] changed inherited model name --- local-addons/morons/security/security.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/local-addons/morons/security/security.xml b/local-addons/morons/security/security.xml index 5ac49d6..7e95750 100644 --- a/local-addons/morons/security/security.xml +++ b/local-addons/morons/security/security.xml @@ -20,7 +20,7 @@ Contributor access - + @@ -30,7 +30,7 @@ PM access - + @@ -48,7 +48,7 @@ PO Contributor Access - + [('user_id','=',user.id)] @@ -56,7 +56,7 @@ PO PM Access - + [('user_id','=',user.id)] From 751f32156228a746bdffb9ff78f53ae662320cfb Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Wed, 20 Dec 2023 22:01:51 +0700 Subject: [PATCH 02/14] Added internal user form for admin accounts --- local-addons/morons/models/contributor.py | 96 +++++++++++------------ local-addons/morons/views/project.xml | 44 +++++++++++ local-addons/morons/views/user.xml | 24 ++++++ 3 files changed, 116 insertions(+), 48 deletions(-) diff --git a/local-addons/morons/models/contributor.py b/local-addons/morons/models/contributor.py index cbe99c9..2418e03 100644 --- a/local-addons/morons/models/contributor.py +++ b/local-addons/morons/models/contributor.py @@ -12,51 +12,51 @@ class InternalUser(models.Model): contributor = fields.Boolean(string='Contributor', default=False) active = fields.Boolean(string='Active', default=True) currency = fields.Many2one('res.currency', string='Currency') - # skype = fields.Char(string='Skype') - # nationality = fields.Many2many('res.lang', required=True) - # country_of_residence = fields.Many2one('res.country', required=True) - # timezone = fields.Selection('_tz_get', - # string='Timezone', - # required=True, - # default=lambda self: self.env.user.tz or 'UTC') - # - # @api.model - # def _tz_get(self): - # return [(x, x) for x in pytz.all_timezones] - # - # # Payment Methods - # paypal = fields.Char('PayPal ID') - # transferwise_id = fields.Char('Wise ID') - # bank_account_number = fields.Char('Bank Account Number') - # bank_name = fields.Char('Bank Name') - # iban = fields.Char('IBAN') - # swift = fields.Char('SWIFT') - # bank_address = fields.Char('Bank Address') - # preferred_payment_method = fields.Selection(selection=[('paypal', 'Paypal'), - # ('transferwise', 'Wise'), - # ('bank', 'Bank Transfer')]) - # - # @api.constrains('paypal') - # def validate_email(self): - # if self.paypal: - # match = re.match( - # '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', - # self.paypal) - # if match is None: - # raise ValidationError('Not a valid email') - # - # # Education and Experience - # dates_attended = fields.Date('Date Attended') - # school = fields.Char('School') - # field_of_study = fields.Char('Field of Study') - # year_obtained = fields.Selection([(num, str(num)) for num in range(1900, datetime.datetime.now().year + 1)], 'Year') - # certificate = fields.Char('Certificate') - # - # @api.constrains('login') - # def validate_email(self): - # if self.login: - # match = re.match( - # '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', - # self.login) - # if match is None: - # raise ValidationError('Not a valid email') + skype = fields.Char(string='Skype') + nationality = fields.Many2many('res.lang', required=True) + country_of_residence = fields.Many2one('res.country', required=True) + timezone = fields.Selection('_tz_get', + string='Timezone', + required=True, + default=lambda self: self.env.user.tz or 'UTC') + + @api.model + def _tz_get(self): + return [(x, x) for x in pytz.all_timezones] + + # Payment Methods + paypal = fields.Char('PayPal ID') + transferwise_id = fields.Char('Wise ID') + bank_account_number = fields.Char('Bank Account Number') + bank_name = fields.Char('Bank Name') + iban = fields.Char('IBAN') + swift = fields.Char('SWIFT') + bank_address = fields.Char('Bank Address') + preferred_payment_method = fields.Selection(selection=[('paypal', 'Paypal'), + ('transferwise', 'Wise'), + ('bank', 'Bank Transfer')]) + + @api.constrains('paypal') + def validate_paypal(self): + if self.paypal: + match = re.match( + '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', + self.paypal) + if match is None: + raise ValidationError('Not a valid email') + + # Education and Experience + dates_attended = fields.Date('Date Attended') + school = fields.Char('School') + field_of_study = fields.Char('Field of Study') + year_obtained = fields.Selection([(str(num), str(num)) for num in range(1900, datetime.datetime.now().year + 1)], 'Year') + certificate = fields.Char('Certificate') + + @api.constrains('login') + def validate_login(self): + if self.login: + match = re.match( + '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', + self.login) + if match is None: + raise ValidationError('Not a valid email') diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index b0462a8..2a77c3c 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -123,11 +123,55 @@ + + + res.users.form.custom + res.users + + + + + Contributor + Currency + Active + Skype + Nationality + Country of Residence + Timezone + + + + + Preferred Payment Method + PayPal ID + Wise ID + Bank Account Number + Bank Name + IBAN + SWIFT + Bank Address + + + + + Dates Attended + School + Field of Study + Year Obtained + Certificate + + + + + + + Internal Users res.users tree,form + [('share', '=', False)] diff --git a/local-addons/morons/views/user.xml b/local-addons/morons/views/user.xml index 170b35d..8f7c3fb 100644 --- a/local-addons/morons/views/user.xml +++ b/local-addons/morons/views/user.xml @@ -12,8 +12,32 @@ + Contributor Currency + Active + Skype + Nationality + Country of Residence + Timezone + + + Preferred Payment Method + PayPal ID + Wise ID + Bank Account Number + Bank Name + IBAN + SWIFT + Bank Address + + + Dates Attended + School + Field of Study + Year Obtained + Certificate + From 3ccaf1f2b1171eb4c2a6c8f5a4474d62ecd70c2f Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Thu, 21 Dec 2023 00:21:04 +0700 Subject: [PATCH 03/14] Added limitation for group_id --- local-addons/morons/models/project.py | 2 +- local-addons/morons/views/project.xml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/local-addons/morons/models/project.py b/local-addons/morons/models/project.py index 30a0a68..4659a79 100644 --- a/local-addons/morons/models/project.py +++ b/local-addons/morons/models/project.py @@ -12,7 +12,7 @@ class MercTransServices(models.Model): _name = "merctrans.services" - _rec_name = "name" + _rec_name = "name" _description = "Services offered by MercTrans" department_list = [ diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index 2a77c3c..7406ad8 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -130,6 +130,10 @@ + User Groups Contributor Currency From d4c56778c50eab0ff3f6264b24d1949d52032580 Mon Sep 17 00:00:00 2001 From: EstherWee <89062424+EstherWee@users.noreply.github.com> Date: Thu, 21 Dec 2023 04:28:54 +0700 Subject: [PATCH 04/14] access rights for Apps menu --- local-addons/morons/views/project.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index b0462a8..16791b3 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -138,5 +138,7 @@ action="action_open_res_users" groups="base.group_system" sequence="5"/> + + \ No newline at end of file From 1667e033cb034af5027579807afe6f3df6c39782 Mon Sep 17 00:00:00 2001 From: EstherWee <89062424+EstherWee@users.noreply.github.com> Date: Thu, 21 Dec 2023 05:06:58 +0700 Subject: [PATCH 05/14] access rights to see all projects --- local-addons/morons/views/project.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index 16791b3..d2afe2a 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -139,6 +139,13 @@ groups="base.group_system" sequence="5"/> - + + + \ No newline at end of file From 7928b53c0dfd9e5e3c106fa5a9c787ae97578cfb Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Thu, 21 Dec 2023 12:51:00 +0700 Subject: [PATCH 06/14] Added invoice model --- local-addons/morons/__manifest__.py | 4 ++-- local-addons/morons/models/__init__.py | 3 ++- local-addons/morons/models/contributor.py | 1 + local-addons/morons/views/project.xml | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/local-addons/morons/__manifest__.py b/local-addons/morons/__manifest__.py index 136904f..ee6a93a 100644 --- a/local-addons/morons/__manifest__.py +++ b/local-addons/morons/__manifest__.py @@ -26,14 +26,14 @@ # 'security/ir.model.access.csv', 'views/project.xml', 'views/user.xml', - "security/ir.model.access.csv", - "security/security.xml", 'data/languages.xml', 'data/currencies.xml', 'data/email_template.xml', 'data/company_data.xml', 'data/services.xml', 'data/tags.xml', + "security/ir.model.access.csv", + "security/security.xml", ], # only loaded in demonstration mode 'demo': [ diff --git a/local-addons/morons/models/__init__.py b/local-addons/morons/models/__init__.py index bba51e2..f953daa 100644 --- a/local-addons/morons/models/__init__.py +++ b/local-addons/morons/models/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- from . import project -from . import contributor \ No newline at end of file +from . import contributor +from . import invoice \ No newline at end of file diff --git a/local-addons/morons/models/contributor.py b/local-addons/morons/models/contributor.py index cc90a68..f659a17 100644 --- a/local-addons/morons/models/contributor.py +++ b/local-addons/morons/models/contributor.py @@ -95,6 +95,7 @@ def validate_paypal(self): year_obtained = fields.Selection([(str(num), str(num)) for num in range(1900, datetime.datetime.now().year + 1)], 'Year') certificate = fields.Char('Certificate') + @api.constrains('login') def validate_login(self): if self.login: diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index 94058e9..3b9fd34 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -141,7 +141,7 @@ - + Contributor Currency Active @@ -168,7 +168,7 @@ - + Dates Attended School Field of Study From 4ae6a609e15d10c36bf7735208cab581f07f305c Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Fri, 22 Dec 2023 13:09:52 +0700 Subject: [PATCH 07/14] Added boilerplate invoice model --- local-addons/morons/models/contributor.py | 7 +++ local-addons/morons/views/project.xml | 55 +++++++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/local-addons/morons/models/contributor.py b/local-addons/morons/models/contributor.py index f659a17..032d2c4 100644 --- a/local-addons/morons/models/contributor.py +++ b/local-addons/morons/models/contributor.py @@ -95,6 +95,13 @@ def validate_paypal(self): year_obtained = fields.Selection([(str(num), str(num)) for num in range(1900, datetime.datetime.now().year + 1)], 'Year') certificate = fields.Char('Certificate') + assigned_records_count = fields.Integer(string='Assigned Records Count', compute='_compute_assigned_records_count') + + def _compute_assigned_records_count(self): + for record in self: + # Count the number of project.task records where this user is in user_ids + count = self.env['project.task'].search_count([('user_ids', 'in', record.id)]) + record.assigned_records_count = count @api.constrains('login') def validate_login(self): diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index 3b9fd34..27a6ab2 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -186,16 +186,63 @@ Internal Users res.users tree,form - - [('share', '=', False)] + + [('share', '=', False)] + + morons list + morons.invoice + + + + + + + + + + + + + + + + + + Invoices + morons.invoice + tree + + + + + + + + + groups="base.group_system"/> + + + + + + + \ No newline at end of file From 95dba022ab5c66a5f3af2d4f626706756ad9efef Mon Sep 17 00:00:00 2001 From: EstherWee <89062424+EstherWee@users.noreply.github.com> Date: Fri, 22 Dec 2023 13:10:16 +0700 Subject: [PATCH 08/14] created 2 new groups --- local-addons/morons/__manifest__.py | 4 ++-- local-addons/morons/security/security.xml | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/local-addons/morons/__manifest__.py b/local-addons/morons/__manifest__.py index 136904f..68b72b9 100644 --- a/local-addons/morons/__manifest__.py +++ b/local-addons/morons/__manifest__.py @@ -24,10 +24,10 @@ # always loaded 'data': [ # 'security/ir.model.access.csv', - 'views/project.xml', - 'views/user.xml', "security/ir.model.access.csv", "security/security.xml", + 'views/project.xml', + 'views/user.xml', 'data/languages.xml', 'data/currencies.xml', 'data/email_template.xml', diff --git a/local-addons/morons/security/security.xml b/local-addons/morons/security/security.xml index 7e95750..4648fb3 100644 --- a/local-addons/morons/security/security.xml +++ b/local-addons/morons/security/security.xml @@ -17,6 +17,16 @@ + + BOD + + + + + Accountants + + + Contributor access From 8ce23a6d61c625d32844331f57adaecf0c52dbde Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Fri, 22 Dec 2023 13:21:04 +0700 Subject: [PATCH 09/14] Added boilerplate invoice model --- local-addons/morons/models/invoice.py | 96 +++++++++++++++++++++++++++ local-addons/morons/views/invoice.xml | 0 local-addons/morons/views/project.xml | 6 +- 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 local-addons/morons/models/invoice.py create mode 100644 local-addons/morons/views/invoice.xml diff --git a/local-addons/morons/models/invoice.py b/local-addons/morons/models/invoice.py new file mode 100644 index 0000000..c9b6219 --- /dev/null +++ b/local-addons/morons/models/invoice.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields, api + +class Invoice(models.Model): + """ + A model representing invoices in the MercTrans system. + + This class extends the basic functionality of Odoo's invoicing system + to meet the specific requirements of MercTrans. It includes features + like a variety of work units, different statuses for invoices and payments, + and the capability to handle different currencies with automatic conversion + to USD. It also manages the link with purchase orders from projects and + calculates payable amounts based on dynamic rates and units. + + Attributes: + _name (str): Identifier for the Odoo model. + invoice_status_list (list of tuples): A predefined list of possible statuses for an invoice. + work_unit_list (list of tuples): A predefined list of work units applicable to an invoice. + payment_status_list (list of tuples): A predefined list of payment statuses for tracking invoice payments. + issue_date (fields.Date): Field for the date when the invoice is issued. + due_date (fields.Date): Field for the date when the invoice payment is due. + sender (fields.Char): Field for the name of the sender of the invoice. + purchase_order (fields.Many2one): Relationship to the 'project.project' model, representing the associated purchase order. + purchase_order_name (fields.Char): Field for displaying the name of the related purchase order, derived from 'purchase_order'. + note (fields.Text): Field for any additional notes or comments on the invoice. + currency (fields.Many2one): Field linking to the 'res.currency' model for specifying the currency used in the invoice. + work_unit (fields.Selection): Field for selecting a work unit from the work_unit_list. + rate (fields.Float): Field for the rate applied in the invoice, dependent on the chosen work unit. + sale_unit (fields.Integer): Field for the number of work units being billed in the invoice. + payable (fields.Monetary): Computed field for the total payable amount in the invoice's currency. + payable_usd (fields.Monetary): Computed field for the total payable amount converted to USD. + status (fields.Selection): Field for the current status of the invoice, selected from invoice_status_list. + payment_status (fields.Selection): Field for the current payment status of the invoice, selected from payment_status_list. + + Methods: + _compute_payable_amount(self): Computes the total payable amount based on the rate and sale unit. + _compute_amount_usd(self): Converts the payable amount into USD based on the current exchange rate and invoice date. + """ + + _name = 'morons.invoice' + + invoice_status_list = [ + ("in progress", "In Progress"), + ("completed", "Completed"), + ("canceled", "Canceled"), + ("draft", "Draft"), + ] + + work_unit_list = [ + ("word", "Word"), + ("hour", "Hour"), + ("page", "Page"), + ("job", "Job"), + ] + + payment_status_list = [ + ("unpaid", "Unpaid"), + ("invoiced", "Invoiced"), + ("paid", "Paid"), + ] + + issue_date = fields.Date(string='Issue Date') + due_date = fields.Date(string='Due Date') + sender = fields.Char(string='Issued By') + + purchase_order = fields.Many2one('project.project', string='Purchase Order') + purchase_order_name = fields.Char(string="Purchase Order Name", related='purchase_order.name', readonly=True) + + note = fields.Text(string='Note') + + currency = fields.Many2one('res.currency', string='Currency') + work_unit = fields.Selection(string='Work Unit', selection=work_unit_list, default='word') + rate = fields.Float(string="Rate", digits=(16, 2)) + sale_unit = fields.Integer(string='Sale Unit') + payable = fields.Monetary(string='Payable', currency_field='currency', compute='_compute_payable_amount', store=True) + payable_usd = fields.Monetary(string='Payable(USD)', currency_field='currency', compute='_compute_amount_usd') + + @api.depends('rate', 'sale_unit') + def _compute_payable_amount(self): + for record in self: + record.payable = record.rate * record.sale_unit + + @api.depends('payable', 'currency') + def _compute_amount_usd(self): + usd_currency_id = self.env.ref('base.USD').id + for record in self: + if record.currency and record.currency.id != usd_currency_id: + conversion_rate = record.currency.with_context(date=record.issue_date).rate + record.payable_usd = record.payable * conversion_rate + else: + record.payable_usd = record.payable + + status = fields.Selection(string='Status', selection=invoice_status_list, default='draft') + payment_status = fields.Selection(string='Payment Status', selection=payment_status_list, default='unpaid') + diff --git a/local-addons/morons/views/invoice.xml b/local-addons/morons/views/invoice.xml new file mode 100644 index 0000000..e69de29 diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index 27a6ab2..904eb2e 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -205,8 +205,8 @@ - + + @@ -215,7 +215,7 @@ Invoices morons.invoice tree - + From 5fd9a433d85276def1791ad30761e5046eef29ce Mon Sep 17 00:00:00 2001 From: EstherWee <89062424+EstherWee@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:43:06 +0700 Subject: [PATCH 10/14] access rights for invoice status --- local-addons/morons/models/invoice.py | 4 +- local-addons/morons/security/security.xml | 49 ++++++++++++++++++++ local-addons/morons/views/project.xml | 55 ++++++++++++++++------- 3 files changed, 91 insertions(+), 17 deletions(-) diff --git a/local-addons/morons/models/invoice.py b/local-addons/morons/models/invoice.py index c9b6219..6e6a4d3 100644 --- a/local-addons/morons/models/invoice.py +++ b/local-addons/morons/models/invoice.py @@ -64,8 +64,8 @@ class Invoice(models.Model): due_date = fields.Date(string='Due Date') sender = fields.Char(string='Issued By') - purchase_order = fields.Many2one('project.project', string='Purchase Order') - purchase_order_name = fields.Char(string="Purchase Order Name", related='purchase_order.name', readonly=True) + # purchase_order = fields.Many2one('project.project', string='Purchase Order') + # purchase_order_name = fields.Char(string="Purchase Order Name", related='purchase_order.name', readonly=True) note = fields.Text(string='Note') diff --git a/local-addons/morons/security/security.xml b/local-addons/morons/security/security.xml index 7e95750..337402a 100644 --- a/local-addons/morons/security/security.xml +++ b/local-addons/morons/security/security.xml @@ -17,6 +17,15 @@ + + BOD + + + + Accountants + + + Contributor access @@ -38,6 +47,46 @@ + + Contributor access to invoice + + + + + + + + + + PM access to invoice + + + + + + + + + + BOD access to invoice + + + + + + + + + + Accountant access to invoice + + + + + + + + + + + + + + + + + + + + + + + morons list morons.invoice - - - - - - - - - - - - + + + + + + + + + + + + Invoices morons.invoice - tree - + tree,form + From 7991358817a3358825ff3f3de7361aec077c069b Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Fri, 22 Dec 2023 16:57:15 +0700 Subject: [PATCH 11/14] Revised invoice model --- local-addons/morons/views/project.xml | 33 +++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index 27a6ab2..c57156b 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -195,27 +195,30 @@ morons list morons.invoice - - - - - - - - - - - - +
+ + + + + + + + + + + + + + +
Invoices morons.invoice - tree - + tree,form + From 7cb73b19d6c1ec74810c0980c53b977c5415d0c7 Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Mon, 25 Dec 2023 14:51:11 +0700 Subject: [PATCH 12/14] Completed payable_usd computation and total contributor records --- local-addons/morons/models/contributor.py | 2 +- local-addons/morons/views/project.xml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/local-addons/morons/models/contributor.py b/local-addons/morons/models/contributor.py index 032d2c4..68e30a0 100644 --- a/local-addons/morons/models/contributor.py +++ b/local-addons/morons/models/contributor.py @@ -95,7 +95,7 @@ def validate_paypal(self): year_obtained = fields.Selection([(str(num), str(num)) for num in range(1900, datetime.datetime.now().year + 1)], 'Year') certificate = fields.Char('Certificate') - assigned_records_count = fields.Integer(string='Assigned Records Count', compute='_compute_assigned_records_count') + assigned_records_count = fields.Integer(string=' Assigned Tasks', compute='_compute_assigned_records_count') def _compute_assigned_records_count(self): for record in self: diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index c57156b..595a587 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -174,6 +174,7 @@ Field of Study Year Obtained Certificate + @@ -191,7 +192,7 @@ [('share', '=', False)] - + morons list morons.invoice @@ -218,7 +219,7 @@ Invoices morons.invoice tree,form - + From 245e0de937e2eaef685f9882485d594abad90408 Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Mon, 25 Dec 2023 14:52:15 +0700 Subject: [PATCH 13/14] Fix: Added invoice model --- local-addons/morons/models/invoice.py | 107 ++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 local-addons/morons/models/invoice.py diff --git a/local-addons/morons/models/invoice.py b/local-addons/morons/models/invoice.py new file mode 100644 index 0000000..0de8988 --- /dev/null +++ b/local-addons/morons/models/invoice.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields, api + +class Invoice(models.Model): + """ + A model representing invoices in the MercTrans system. + + This class extends the basic functionality of Odoo's invoicing system + to meet the specific requirements of MercTrans. It includes features + like a variety of work units, different statuses for invoices and payments, + and the capability to handle different currencies with automatic conversion + to USD. It also manages the link with purchase orders from projects and + calculates payable amounts based on dynamic rates and units. + + Attributes: + _name (str): Identifier for the Odoo model. + invoice_status_list (list of tuples): A predefined list of possible statuses for an invoice. + work_unit_list (list of tuples): A predefined list of work units applicable to an invoice. + payment_status_list (list of tuples): A predefined list of payment statuses for tracking invoice payments. + issue_date (fields.Date): Field for the date when the invoice is issued. + due_date (fields.Date): Field for the date when the invoice payment is due. + sender (fields.Char): Field for the name of the sender of the invoice. + purchase_order (fields.Many2one): Relationship to the 'project.project' model, representing the associated purchase order. + purchase_order_name (fields.Char): Field for displaying the name of the related purchase order, derived from 'purchase_order'. + note (fields.Text): Field for any additional notes or comments on the invoice. + currency (fields.Many2one): Field linking to the 'res.currency' model for specifying the currency used in the invoice. + work_unit (fields.Selection): Field for selecting a work unit from the work_unit_list. + rate (fields.Float): Field for the rate applied in the invoice, dependent on the chosen work unit. + sale_unit (fields.Integer): Field for the number of work units being billed in the invoice. + payable (fields.Monetary): Computed field for the total payable amount in the invoice's currency. + payable_usd (fields.Monetary): Computed field for the total payable amount converted to USD. + status (fields.Selection): Field for the current status of the invoice, selected from invoice_status_list. + payment_status (fields.Selection): Field for the current payment status of the invoice, selected from payment_status_list. + + Methods: + _compute_payable_amount(self): Computes the total payable amount based on the rate and sale unit. + _compute_amount_usd(self): Converts the payable amount into USD based on the current exchange rate and invoice date. + """ + + _name = 'morons.invoice' + + invoice_status_list = [ + ("in progress", "In Progress"), + ("completed", "Completed"), + ("canceled", "Canceled"), + ("draft", "Draft"), + ] + + work_unit_list = [ + ("word", "Word"), + ("hour", "Hour"), + ("page", "Page"), + ("job", "Job"), + ] + + payment_status_list = [ + ("unpaid", "Unpaid"), + ("invoiced", "Invoiced"), + ("paid", "Paid"), + ] + + issue_date = fields.Date(string='Issue Date') + due_date = fields.Date(string='Due Date') + sender = fields.Char(string='Issued By') + + purchase_order = fields.Many2one('project.task', string='Purchase Order') + + note = fields.Text(string='Note') + + currency = fields.Many2one('res.currency', string='Currency') + work_unit = fields.Selection(string='Work Unit', selection=work_unit_list, default='word') + rate = fields.Float(string="Rate", digits=(16, 2)) + sale_unit = fields.Integer(string='Sale Unit') + payable = fields.Monetary(string='Payable', currency_field='currency', compute='_compute_payable_amount', store=True, readonly=True) + usd_currency_id = fields.Many2one('res.currency', string='USD Currency', default=lambda self: self.env.ref('base.USD')) + payable_usd = fields.Monetary(string='Payable(USD)', currency_field='usd_currency_id', compute='_compute_amount_usd') + + @api.depends('rate', 'sale_unit') + def _compute_payable_amount(self): + for record in self: + record.payable = record.rate * record.sale_unit + + @api.depends('payable') + def _compute_amount_usd(self): + """ + For now, it is hardcoded to convert from VND to USD and EUR to USD. + (TODO) Auto compute regardless of currency. + """ + for record in self: + if record.currency.name == 'VND': + record.payable_usd = record.payable * 0.000041 + elif record.currency.name == 'EUR': + record.payable_usd = record.payable * 1.10 + else: + record.payable_usd = record.payable + + # @api.depends('payable', 'currency') + # def _compute_payable_usd(self): + # for record in self: + # USD = self.env['res.currency'].search([('name', '=', 'USD')]) + # curr = self.env['res.currency'].search([('name', '=', 'VND')]) + # record.payable_usd = USD.compute(record.payable, curr) + + status = fields.Selection(string='Status', selection=invoice_status_list, default='draft') + payment_status = fields.Selection(string='Payment Status', selection=payment_status_list, default='unpaid') + From 688c6f8dc38f5f05bf0b419243e6b1b4790a6c78 Mon Sep 17 00:00:00 2001 From: Toh Zhengfeng Date: Mon, 25 Dec 2023 16:19:37 +0700 Subject: [PATCH 14/14] Added increments for invoice --- local-addons/morons/models/invoice.py | 11 +++- local-addons/morons/views/project.xml | 91 ++++++++++++++------------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/local-addons/morons/models/invoice.py b/local-addons/morons/models/invoice.py index 0de8988..6111098 100644 --- a/local-addons/morons/models/invoice.py +++ b/local-addons/morons/models/invoice.py @@ -59,10 +59,19 @@ class Invoice(models.Model): ("invoiced", "Invoiced"), ("paid", "Paid"), ] + + invoice_id = fields.Char(string='Invoice ID', required=True, copy=False, readonly=True, index=True, default=lambda self: 'New') + + @api.model + def create(self, vals): + if vals.get('invoice_id', 'New') == 'New': + vals['invoice_id'] = self.env['ir.sequence'].next_by_code('morons.invoice') or 'New' + result = super(Invoice, self).create(vals) + return result issue_date = fields.Date(string='Issue Date') due_date = fields.Date(string='Due Date') - sender = fields.Char(string='Issued By') + sender = fields.Many2one('res.user',string='Issued By') purchase_order = fields.Many2one('project.task', string='Purchase Order') diff --git a/local-addons/morons/views/project.xml b/local-addons/morons/views/project.xml index b95b754..47e2873 100644 --- a/local-addons/morons/views/project.xml +++ b/local-addons/morons/views/project.xml @@ -192,49 +192,69 @@ [('share', '=', False)] + + + Morons Invoice + morons.invoice + INV- + 5 + 1 + + + morons list morons.invoice -
- - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + +
+
+ morons list morons.invoice - - - - - - - - - - - - + + + + + + + + + + + + + + Invoices morons.invoice @@ -248,9 +268,7 @@ - + action="action_open_invoice"/> - - - - - - -