diff --git a/.dockerignore b/.dockerignore index 241e560..72e8ffc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1 @@ * - diff --git a/README.md b/README.md index 0b3b073..a084e5c 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ $ gunzip .sql.gz $ psql beescoop < .sql ``` -##### 4) deactivate cron jobs and mails +##### 4) deactivate cron jobs and mails ``` $ psql -d beescoop -c "UPDATE ir_cron SET active='f' WHERE active='t';" @@ -131,4 +131,3 @@ $ python odoo.py -c $ODOO_HOME/odoo.conf -u all -d beescoop --stop-after-init insert into member_card (active, barcode, partner_id, responsible_id, activation_date) select 't', barcode, id, 1, '2016-01-01' from res_partner where barcode is not null; update res_partner set eater = 'worker_eater' where barcode is not null; ``` - diff --git a/beesdoo_account/readme/CONTRIBUTORS.rst b/beesdoo_account/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_account/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_base/__manifest__.py b/beesdoo_base/__manifest__.py index 2ad0665..1ab2011 100644 --- a/beesdoo_base/__manifest__.py +++ b/beesdoo_base/__manifest__.py @@ -6,34 +6,24 @@ # - Thibault François # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': "Beescoop Base Module", - - 'summary': """ + "name": "Beescoop Base Module", + "summary": """ Module that customize the base module and contains some python tools """, - - 'description': """ - """, - - 'author': "Beescoop - Cellule IT", - 'website': "https://github.com/beescoop/Obeesdoo", - - 'category': 'Sales', - 'version': '12.0.1.0.0', - - 'depends': ['point_of_sale', 'purchase', 'portal', 'partner_firstname'], - - 'data': [ - 'security/groups.xml', - 'security/ir.model.access.csv', - 'views/partner.xml', - 'wizard/views/member_card.xml', - 'wizard/views/partner.xml', - 'report/beescard.xml', + "author": "Beescoop - Cellule IT, Coop IT Easy SCRLfs", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Sales", + "version": "12.0.1.0.0", + "depends": ["point_of_sale", "purchase", "portal", "partner_firstname"], + "data": [ + "security/groups.xml", + "security/ir.model.access.csv", + "views/partner.xml", + "wizard/views/member_card.xml", + "wizard/views/partner.xml", + "report/beescard.xml", ], - 'installable': True, - 'demo': [ - 'demo/cooperators.xml', - 'demo/eaters.xml', - ] + "installable": True, + "demo": ["demo/cooperators.xml", "demo/eaters.xml",], + "license": "AGPL-3", } diff --git a/beesdoo_base/demo/eaters.xml b/beesdoo_base/demo/eaters.xml index 13dc5f3..70a3451 100644 --- a/beesdoo_base/demo/eaters.xml +++ b/beesdoo_base/demo/eaters.xml @@ -40,4 +40,3 @@ - diff --git a/beesdoo_base/models/membercard.py b/beesdoo_base/models/membercard.py index 7ef66b1..4967350 100644 --- a/beesdoo_base/models/membercard.py +++ b/beesdoo_base/models/membercard.py @@ -1,24 +1,35 @@ -from odoo import models, fields, api import uuid -class MemberCard(models.Model): +from odoo import api, fields, models + +class MemberCard(models.Model): def _get_current_user(self): return self.env.uid def _compute_bar_code(self): - rule = self.env['barcode.rule'].search([('name', '=', 'Customer Barcodes')])[0] + rule = self.env["barcode.rule"].search( + [("name", "=", "Customer Barcodes")] + )[0] size = 13 - len(rule.pattern) ean = rule.pattern + str(uuid.uuid4().fields[-1])[:size] - return ean[0:12] + str(self.env['barcode.nomenclature'].ean_checksum(ean)) + return ean[0:12] + str( + self.env["barcode.nomenclature"].ean_checksum(ean) + ) - _name = 'member.card' - _order = 'create_date desc' + _name = "member.card" + _order = "create_date desc" _description = "Member Card" valid = fields.Boolean(default=True, string="Active") - barcode = fields.Char("Barcode", oldname='ean13', default=_compute_bar_code) - partner_id = fields.Many2one('res.partner') #, default=_get_current_client) - responsible_id = fields.Many2one('res.users', default=_get_current_user, string="Responsible") + barcode = fields.Char( + "Barcode", oldname="ean13", default=_compute_bar_code + ) + partner_id = fields.Many2one( + "res.partner" + ) # , default=_get_current_client) + responsible_id = fields.Many2one( + "res.users", default=_get_current_user, string="Responsible" + ) end_date = fields.Date(readonly=True, string="Expiration Date") comment = fields.Char("Reason", required=True) diff --git a/beesdoo_base/models/partner.py b/beesdoo_base/models/partner.py index 6ebaee2..7fba94c 100644 --- a/beesdoo_base/models/partner.py +++ b/beesdoo_base/models/partner.py @@ -1,24 +1,42 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError + class Partner(models.Model): - _inherit = 'res.partner' + _inherit = "res.partner" - eater = fields.Selection([('eater', 'Eater'), ('worker_eater', 'Worker and Eater')], string="Eater/Worker") - child_eater_ids = fields.One2many("res.partner", "parent_eater_id", domain=[('customer', '=', True), - ('eater', '=', 'eater')]) - parent_eater_id = fields.Many2one("res.partner", string="Parent Worker", readonly=True) - barcode = fields.Char(compute="_get_bar_code", string='Barcode', store=True) - parent_barcode = fields.Char(compute="_get_bar_code", string='Parent Barcode', store=True) - member_card_ids = fields.One2many('member.card', 'partner_id') + eater = fields.Selection( + [("eater", "Eater"), ("worker_eater", "Worker and Eater")], + string="Eater/Worker", + ) + child_eater_ids = fields.One2many( + "res.partner", + "parent_eater_id", + domain=[("customer", "=", True), ("eater", "=", "eater")], + ) + parent_eater_id = fields.Many2one( + "res.partner", string="Parent Worker", readonly=True + ) + barcode = fields.Char( + compute="_get_bar_code", string="Barcode", store=True + ) + parent_barcode = fields.Char( + compute="_get_bar_code", string="Parent Barcode", store=True + ) + member_card_ids = fields.One2many("member.card", "partner_id") - member_card_to_be_printed = fields.Boolean('Print BEES card?') - last_printed = fields.Datetime('Last printed on') + member_card_to_be_printed = fields.Boolean("Print BEES card?") + last_printed = fields.Datetime("Last printed on") - @api.depends('parent_eater_id', 'parent_eater_id.barcode', 'eater', 'member_card_ids') + @api.depends( + "parent_eater_id", + "parent_eater_id.barcode", + "eater", + "member_card_ids", + ) def _get_bar_code(self): for rec in self: - if rec.eater == 'eater': + if rec.eater == "eater": rec.parent_barcode = rec.parent_eater_id.barcode elif rec.member_card_ids: for c in rec.member_card_ids: @@ -29,45 +47,49 @@ class Partner(models.Model): def write(self, values): for rec in self: if ( - values.get('parent_eater_id') + values.get("parent_eater_id") and rec.parent_eater_id and rec.parent_eater_id.id != values.get("parent_eater_id") ): - raise ValidationError(_('You try to assign a eater to a worker but this eater is already assign to %s please remove it before') % rec.parent_eater_id.name) + raise ValidationError( + _( + "You try to assign a eater to a worker but this eater is already assign to %s please remove it before" + ) + % rec.parent_eater_id.name + ) # replace many2many command when writing on child_eater_ids to just remove the link - if 'child_eater_ids' in values: - for command in values['child_eater_ids']: + if "child_eater_ids" in values: + for command in values["child_eater_ids"]: if command[0] == 2: command[0] = 3 return super(Partner, self).write(values) def _deactivate_active_cards(self): self.ensure_one() - for card in self.member_card_ids.filtered('valid'): + for card in self.member_card_ids.filtered("valid"): card.valid = False card.end_date = fields.Date.today() @api.multi def _new_card(self, reason, user_id, barcode=False): card_data = { - 'partner_id' : self.id, - 'responsible_id' : user_id, - 'comment' : reason, + "partner_id": self.id, + "responsible_id": user_id, + "comment": reason, } if barcode: - card_data['barcode'] = barcode - self.env['member.card'].create(card_data) + card_data["barcode"] = barcode + self.env["member.card"].create(card_data) @api.multi def _new_eater(self, surname, name, email): partner_data = { - - 'lastname' : name, - 'firstname' : surname, - 'is_customer' : True, - 'eater' : 'eater', - 'parent_eater_id' : self.id, - 'email' : email, - 'country_id' : self.country_id.id - } - return self.env['res.partner'].create(partner_data) + "lastname": name, + "firstname": surname, + "is_customer": True, + "eater": "eater", + "parent_eater_id": self.id, + "email": email, + "country_id": self.country_id.id, + } + return self.env["res.partner"].create(partner_data) diff --git a/beesdoo_base/readme/CONTRIBUTORS.rst b/beesdoo_base/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_base/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_base/security/ir.model.access.csv b/beesdoo_base/security/ir.model.access.csv index a97f8e8..abe97b5 100644 --- a/beesdoo_base/security/ir.model.access.csv +++ b/beesdoo_base/security/ir.model.access.csv @@ -1,2 +1,2 @@ -"id","name","model_id/id","group_id/id","perm_read","perm_write","perm_create","perm_unlink" -"member_card_read_all","member card read all","beesdoo_base.model_member_card","","True","False","False","False" +"id","name","model_id/id","group_id/id","perm_read","perm_write","perm_create","perm_unlink" +"member_card_read_all","member card read all","beesdoo_base.model_member_card","","True","False","False","False" diff --git a/beesdoo_base/wizard/member_card.py b/beesdoo_base/wizard/member_card.py index d3b0a7a..bb209a2 100644 --- a/beesdoo_base/wizard/member_card.py +++ b/beesdoo_base/wizard/member_card.py @@ -1,4 +1,5 @@ -from odoo import models, fields, api +from odoo import api, fields, models + class NewMemberCardWizard(models.TransientModel): """ @@ -6,49 +7,61 @@ class NewMemberCardWizard(models.TransientModel): The user can only define the raison why a new card is needed and the eater/worker that is concerned. """ - _name = 'membercard.new.wizard' + + _name = "membercard.new.wizard" _description = "Member Card" def _get_default_partner(self): - return self.env.context['active_id'] + return self.env.context["active_id"] - new_comment = fields.Char('Reason', required=True) - partner_id = fields.Many2one('res.partner', default=_get_default_partner) - force_barcode = fields.Char('Force Barcode', groups="beesdoo_base.group_force_barcode") + new_comment = fields.Char("Reason", required=True) + partner_id = fields.Many2one("res.partner", default=_get_default_partner) + force_barcode = fields.Char( + "Force Barcode", groups="beesdoo_base.group_force_barcode" + ) @api.one def create_new_card(self): client = self.partner_id.sudo() client._deactivate_active_cards() - client._new_card(self.new_comment, self.env.uid, barcode=self.force_barcode) + client._new_card( + self.new_comment, self.env.uid, barcode=self.force_barcode + ) client.member_card_to_be_printed = True class RequestMemberCardPrintingWizard(models.TransientModel): - _name = 'membercard.requestprinting.wizard' + _name = "membercard.requestprinting.wizard" _description = "Member Card - Request Print Wizard" def _get_selected_partners(self): - return self.env.context['active_ids'] - - partner_ids = fields.Many2many('res.partner', default=_get_selected_partners) + return self.env.context["active_ids"] + partner_ids = fields.Many2many( + "res.partner", default=_get_selected_partners + ) @api.one def request_printing(self): - self.partner_ids.write({'member_card_to_be_printed' : True}) + self.partner_ids.write({"member_card_to_be_printed": True}) class SetAsPrintedWizard(models.TransientModel): - _name = 'membercard.set_as_printed.wizard' + _name = "membercard.set_as_printed.wizard" _description = "Member card - Set as printed wizard" def _get_selected_partners(self): - return self.env.context['active_ids'] + return self.env.context["active_ids"] - partner_ids = fields.Many2many('res.partner', default=_get_selected_partners) + partner_ids = fields.Many2many( + "res.partner", default=_get_selected_partners + ) @api.one def set_as_printed(self): - self.partner_ids.write({'member_card_to_be_printed' : False, - 'last_printed' : fields.Datetime.now()}) + self.partner_ids.write( + { + "member_card_to_be_printed": False, + "last_printed": fields.Datetime.now(), + } + ) diff --git a/beesdoo_base/wizard/partner.py b/beesdoo_base/wizard/partner.py index 5862238..d3c3580 100644 --- a/beesdoo_base/wizard/partner.py +++ b/beesdoo_base/wizard/partner.py @@ -1,20 +1,22 @@ -from odoo import models, fields, api +from odoo import api, fields, models + class NewEaterWizard(models.TransientModel): """ A transient model for the creation of a eater related to a worker. """ - _name = 'eater.new.wizard' - _description = 'eater.new.wizard' + + _name = "eater.new.wizard" + _description = "eater.new.wizard" def _get_default_partner(self): - return self.env.context['active_id'] + return self.env.context["active_id"] - first_name = fields.Char('First Name', required=True) - last_name = fields.Char('Last Name', required=True) - email = fields.Char('Email') + first_name = fields.Char("First Name", required=True) + last_name = fields.Char("Last Name", required=True) + email = fields.Char("Email") - partner_id = fields.Many2one('res.partner', default=_get_default_partner) + partner_id = fields.Many2one("res.partner", default=_get_default_partner) @api.one def create_new_eater(self): diff --git a/beesdoo_base/wizard/portal_wizard.py b/beesdoo_base/wizard/portal_wizard.py index 6fca72c..ef2b8e3 100644 --- a/beesdoo_base/wizard/portal_wizard.py +++ b/beesdoo_base/wizard/portal_wizard.py @@ -1,25 +1,29 @@ -from odoo import models, fields, api -from odoo import SUPERUSER_ID +from odoo import SUPERUSER_ID, api, fields, models + class BeesdooWizard(models.TransientModel): - _inherit = 'portal.wizard' + _inherit = "portal.wizard" - @api.onchange('portal_id') + @api.onchange("portal_id") def onchange_portal(self): # for each partner, determine corresponding portal.wizard.user records - res_partner = self.env['res.partner'] - partner_ids = self._context.get('active_ids', []) + res_partner = self.env["res.partner"] + partner_ids = self._context.get("active_ids", []) contact_ids = set() for partner in res_partner.browse(partner_ids): - for contact in (partner.child_ids | partner): + for contact in partner.child_ids | partner: # make sure that each contact appears at most once in the list if contact.id not in contact_ids: contact_ids.add(contact.id) - in_portal = self.portal_id in contact.user_ids.mapped('groups_id') - self.user_ids |= self.env['portal.wizard.user'].new({ - 'partner_id': contact.id, - 'email': contact.email, - 'in_portal': in_portal, - }) + in_portal = self.portal_id in contact.user_ids.mapped( + "groups_id" + ) + self.user_ids |= self.env["portal.wizard.user"].new( + { + "partner_id": contact.id, + "email": contact.email, + "in_portal": in_portal, + } + ) diff --git a/beesdoo_crelan_csv/__manifest__.py b/beesdoo_crelan_csv/__manifest__.py index 647f2c8..5bba8e0 100644 --- a/beesdoo_crelan_csv/__manifest__.py +++ b/beesdoo_crelan_csv/__manifest__.py @@ -3,21 +3,16 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': "Beescoop Crelan Import module", - - 'summary': """ + "name": "Beescoop Crelan Import module", + "summary": """ Import Crelan CSV Wizard """, - - 'description': """ + "description": """ """, - - 'author': "Beescoop - Cellule IT", - 'website': "https://github.com/beescoop/Obeesdoo", - - 'category': 'Accounting & Finance', - 'version': '12.0.1.0.0', - - 'depends': ['account_bank_statement_import'], - 'installable': True, + "author": "Beescoop - Cellule IT", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Accounting & Finance", + "version": "12.0.1.0.0", + "depends": ["account_bank_statement_import"], + "installable": True, } diff --git a/beesdoo_crelan_csv/models/account_journal.py b/beesdoo_crelan_csv/models/account_journal.py index 98517c8..1080a6f 100644 --- a/beesdoo_crelan_csv/models/account_journal.py +++ b/beesdoo_crelan_csv/models/account_journal.py @@ -6,5 +6,5 @@ class AccountJournal(models.Model): def _get_bank_statements_available_import_formats(self): formats_list = super()._get_bank_statements_available_import_formats() - formats_list.append('Crelan') + formats_list.append("Crelan") return formats_list diff --git a/beesdoo_crelan_csv/wizard/import_crelan_csv.py b/beesdoo_crelan_csv/wizard/import_crelan_csv.py index bd5d2d9..05cd334 100644 --- a/beesdoo_crelan_csv/wizard/import_crelan_csv.py +++ b/beesdoo_crelan_csv/wizard/import_crelan_csv.py @@ -1,8 +1,9 @@ -from io import StringIO import csv import datetime import hashlib -from odoo import models, _ +from io import StringIO + +from odoo import _, models ACCOUNT = "Compte donneur d'ordre" CURRENCY = "Devise" @@ -13,83 +14,125 @@ COUNTERPART_NAME = "Contrepartie" COMMUNICATION = "Communication" TRANSACTION_TYPE = "Type d'opération" + class CodaBankStatementImport(models.TransientModel): - _inherit = 'account.bank.statement.import' + _inherit = "account.bank.statement.import" _date_format = "%d/%m/%Y" _decimal_sep = "." _csv_delimiter = ";" _csv_quote = '"' - - _header = ['Date', 'Montant', 'Devise', 'Contrepartie', 'Compte contrepartie', "Type d'opération", - 'Communication', "Compte donneur d'ordre"] + _header = [ + "Date", + "Montant", + "Devise", + "Contrepartie", + "Compte contrepartie", + "Type d'opération", + "Communication", + "Compte donneur d'ordre", + ] def _generate_note_crelan(self, move): notes = [] - notes.append("%s: %s" % (_('Counter Party Name'), move[COUNTERPART_NAME])) - notes.append("%s: %s" % (_('Counter Party Account'), move[COUNTERPART_NUMBER])) - notes.append("%s: %s" % (_('Communication'), move[COMMUNICATION])) - return '\n'.join(notes) + notes.append( + "{}: {}".format(_("Counter Party Name"), move[COUNTERPART_NAME]) + ) + notes.append( + "{}: {}".format(_("Counter Party Account"), move[COUNTERPART_NUMBER]) + ) + notes.append("{}: {}".format(_("Communication"), move[COMMUNICATION])) + return "\n".join(notes) def _get_move_value_crelan(self, move, sequence): move_data = { - 'name': move[TRANSACTION_TYPE] + ": " + move[COMMUNICATION], - 'note': self._generate_note_crelan(move), - 'date': self._to_iso_date(move[DATE]), - 'amount': float(move[AMOUNT]), - 'account_number': move[COUNTERPART_NUMBER], # Ok - 'partner_name': move[COUNTERPART_NAME], # Ok - 'ref': move[DATE] + '-' + move[AMOUNT] + '-' + move[COUNTERPART_NUMBER] + '-' + move[COUNTERPART_NAME], - 'sequence': sequence, # Ok - 'unique_import_id': move[DATE] + '-' + move[AMOUNT] + '-' + move[COUNTERPART_NUMBER] + '-' + - move[COUNTERPART_NAME] + '-' + hashlib.new('md5', move[COMMUNICATION].encode()).hexdigest() + "name": move[TRANSACTION_TYPE] + ": " + move[COMMUNICATION], + "note": self._generate_note_crelan(move), + "date": self._to_iso_date(move[DATE]), + "amount": float(move[AMOUNT]), + "account_number": move[COUNTERPART_NUMBER], # Ok + "partner_name": move[COUNTERPART_NAME], # Ok + "ref": move[DATE] + + "-" + + move[AMOUNT] + + "-" + + move[COUNTERPART_NUMBER] + + "-" + + move[COUNTERPART_NAME], + "sequence": sequence, # Ok + "unique_import_id": move[DATE] + + "-" + + move[AMOUNT] + + "-" + + move[COUNTERPART_NUMBER] + + "-" + + move[COUNTERPART_NAME] + + "-" + + hashlib.new("md5", move[COMMUNICATION].encode()).hexdigest(), } return move_data - def _get_statement_data_crelan(self, balance_start, balance_end, begin_date, end_date): + def _get_statement_data_crelan( + self, balance_start, balance_end, begin_date, end_date + ): statement_data = { - 'name': _("Bank Statement from %s to %s") % (begin_date, end_date), - 'date': self._to_iso_date(end_date), - 'balance_start': balance_start, # Ok - 'balance_end_real' : balance_end, # Ok - 'transactions' : [] + "name": _("Bank Statement from %s to %s") % (begin_date, end_date), + "date": self._to_iso_date(end_date), + "balance_start": balance_start, # Ok + "balance_end_real": balance_end, # Ok + "transactions": [], } return statement_data - + def _get_acc_number_crelan(self, acc_number): # Check if we match the exact acc_number or the end of an acc number - journal = self.env['account.journal'].search([('bank_acc_number', '=like', '%' + acc_number)]) + journal = self.env["account.journal"].search( + [("bank_acc_number", "=like", "%" + acc_number)] + ) if not journal or len(journal) > 1: # If not found or ambiguious return acc_number - + return journal.bank_acc_number def _get_acc_balance_crelan(self, acc_number): if not self.init_balance == None: return self.init_balance - journal = self.env['account.journal'].search([('bank_acc_number', '=like', '%' + acc_number)]) + journal = self.env["account.journal"].search( + [("bank_acc_number", "=like", "%" + acc_number)] + ) currency = journal.currency_id or journal.company_id.currency_id if not journal or len(journal) > 1: # If not found or ambiguious self.init_balance = 0.0 else: - lang = self._context.get('lang', 'en_US') - l = self.env['res.lang'].search([('code', '=', lang)]) - balance = journal.get_journal_dashboard_datas()['last_balance'][:-1] - self.init_balance = float(balance.replace(currency.symbol, '').strip().replace(l.thousands_sep, '').replace(l.decimal_point, '.')) + lang = self._context.get("lang", "en_US") + l = self.env["res.lang"].search([("code", "=", lang)]) + balance = journal.get_journal_dashboard_datas()["last_balance"][ + :-1 + ] + self.init_balance = float( + balance.replace(currency.symbol, "") + .strip() + .replace(l.thousands_sep, "") + .replace(l.decimal_point, ".") + ) return self.init_balance def _to_iso_date(self, orig_date): - date_obj = datetime.datetime.strptime(orig_date, self._date_format) - return date_obj.strftime('%Y-%m-%d') + date_obj = datetime.datetime.strptime(orig_date, self._date_format) + return date_obj.strftime("%Y-%m-%d") def _parse_file(self, data_file): try: csv_file = StringIO(data_file.decode()) - data = csv.DictReader(csv_file, delimiter=self._csv_delimiter, quotechar=self._csv_quote) + data = csv.DictReader( + csv_file, + delimiter=self._csv_delimiter, + quotechar=self._csv_quote, + ) if not data.fieldnames == self._header: raise ValueError() except ValueError: @@ -113,6 +156,12 @@ class CodaBankStatementImport(models.TransientModel): transactions.append(self._get_move_value_crelan(statement, i)) sum_transaction += float(statement[AMOUNT]) i += 1 - stmt = self._get_statement_data_crelan(balance, balance + sum_transaction, begin_date, end_date) - stmt['transactions'] = transactions - return currency_code, self._get_acc_number_crelan(account_number), [stmt] + stmt = self._get_statement_data_crelan( + balance, balance + sum_transaction, begin_date, end_date + ) + stmt["transactions"] = transactions + return ( + currency_code, + self._get_acc_number_crelan(account_number), + [stmt], + ) diff --git a/beesdoo_easy_my_coop/__manifest__.py b/beesdoo_easy_my_coop/__manifest__.py index c3e3ad4..347bcf8 100644 --- a/beesdoo_easy_my_coop/__manifest__.py +++ b/beesdoo_easy_my_coop/__manifest__.py @@ -1,35 +1,28 @@ { - 'name': "Beescoop link with easy my coop", - - 'summary': """ + "name": "Beescoop link with easy my coop", + "summary": """ Module that made the link between beesdoo customization and easy_my_coop """, - - 'description': """ + "description": """ """, - - 'author': "BEES coop, Coop IT Easy", - 'website': "https://github.com/beescoop/Obeesdoo", - - 'category': 'Cooperative management', - 'version': '12.0.1.0.0', - - 'depends': ['beesdoo_base', - 'beesdoo_shift', - 'easy_my_coop', - 'easy_my_coop_website', - 'partner_age', - ], - - 'data': [ - 'views/res_company.xml', - 'views/subscription_request.xml', - 'views/subscription_templates.xml', - 'views/product.xml' + "author": "BEES coop, Coop IT Easy", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Cooperative management", + "version": "12.0.1.0.0", + "depends": [ + "beesdoo_base", + "beesdoo_shift", + "easy_my_coop", + "easy_my_coop_website", + "partner_age", ], - 'demo': [ - 'demo/product_share.xml', + "data": [ + "views/res_company.xml", + "views/subscription_request.xml", + "views/subscription_templates.xml", + "views/product.xml", ], - 'auto_install': True, + "demo": ["demo/product_share.xml"], + "auto_install": True, } diff --git a/beesdoo_easy_my_coop/controllers/main.py b/beesdoo_easy_my_coop/controllers/main.py index 5e1cff4..c259a89 100644 --- a/beesdoo_easy_my_coop/controllers/main.py +++ b/beesdoo_easy_my_coop/controllers/main.py @@ -1,19 +1,22 @@ from odoo import http from odoo.http import request -from odoo.addons.easy_my_coop_website.controllers.main import WebsiteSubscription as Base +from odoo.addons.easy_my_coop_website.controllers.main import ( + WebsiteSubscription as Base, +) -class WebsiteSubscription(Base): +class WebsiteSubscription(Base): def fill_values(self, values, is_company, logged, load_from_user=False): - values = super(WebsiteSubscription, self).fill_values(values, - is_company, - logged, - load_from_user) - cmp = request.env['res.company']._company_default_get() - values.update({ - 'display_info_session': cmp.display_info_session_confirmation, - 'info_session_required': cmp.info_session_confirmation_required, - 'info_session_text': cmp.info_session_confirmation_text, - }) + values = super(WebsiteSubscription, self).fill_values( + values, is_company, logged, load_from_user + ) + cmp = request.env["res.company"]._company_default_get() + values.update( + { + "display_info_session": cmp.display_info_session_confirmation, + "info_session_required": cmp.info_session_confirmation_required, + "info_session_text": cmp.info_session_confirmation_text, + } + ) return values diff --git a/beesdoo_easy_my_coop/models/product.py b/beesdoo_easy_my_coop/models/product.py index f8828e9..bc4c96d 100644 --- a/beesdoo_easy_my_coop/models/product.py +++ b/beesdoo_easy_my_coop/models/product.py @@ -1,9 +1,9 @@ -from odoo import models, fields +from odoo import fields, models class ProductTemplate(models.Model): - _inherit = 'product.template' + _inherit = "product.template" max_nb_eater_allowed = fields.Integer( string="Max number of eater allowed", @@ -11,14 +11,14 @@ class ProductTemplate(models.Model): help=( "Maximum number of eater allowed for the owner of the share. " "A negative value means no maximum." - ) + ), ) allow_working = fields.Boolean( string="Allow owner to work?", help=( "Owner of this type of share are allowed to participate to the " "shift system." - ) + ), ) allow_shopping = fields.Boolean( string="Allow owner to shop?", diff --git a/beesdoo_easy_my_coop/models/res_company.py b/beesdoo_easy_my_coop/models/res_company.py index 7be05ce..0309714 100644 --- a/beesdoo_easy_my_coop/models/res_company.py +++ b/beesdoo_easy_my_coop/models/res_company.py @@ -1,12 +1,12 @@ # Copyright 2019 Coop IT Easy SCRLfs # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models class ResCompany(models.Model): - _inherit = 'res.company' + _inherit = "res.company" display_info_session_confirmation = fields.Boolean( help="Choose to display a info session checkbox on the cooperator" " website form." @@ -17,19 +17,21 @@ class ResCompany(models.Model): info_session_confirmation_text = fields.Html( translate=True, help="Text to display aside the checkbox to confirm" - " participation to an info session." + " participation to an info session.", ) - @api.onchange('info_session_confirmation_required') + @api.onchange("info_session_confirmation_required") def onchange_info_session_confirmatio_required(self): if self.info_session_confirmation_required: self.display_info_session_confirmation = True - _sql_constraints = [( - 'info_session_approval_constraint', - """CHECK ((info_session_confirmation_required=FALSE + _sql_constraints = [ + ( + "info_session_approval_constraint", + """CHECK ((info_session_confirmation_required=FALSE AND display_info_session_confirmation=FALSE) OR display_info_session_confirmation=TRUE) """, - "Approval can't be mandatory and not displayed." - )] + "Approval can't be mandatory and not displayed.", + ) + ] diff --git a/beesdoo_easy_my_coop/models/res_partner.py b/beesdoo_easy_my_coop/models/res_partner.py index de69114..4945235 100644 --- a/beesdoo_easy_my_coop/models/res_partner.py +++ b/beesdoo_easy_my_coop/models/res_partner.py @@ -1,22 +1,21 @@ # Copyright 2019-2020 Coop IT Easy SCRLfs # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError class Partner(models.Model): - _inherit = 'res.partner' + _inherit = "res.partner" info_session_confirmed = fields.Boolean( - string="Confirmed presence to info session", - default=False, + string="Confirmed presence to info session", default=False ) is_worker = fields.Boolean( compute="_is_worker", search="_search_worker", readonly=True, - related="" + related="", ) def _cooperator_share_type(self): @@ -27,16 +26,17 @@ class Partner(models.Model): share_type = None if self.cooperator_type: share_type = ( - self.env['product.template'] - .search([('default_code', '=', self.cooperator_type)]) + self.env["product.template"].search( + [("default_code", "=", self.cooperator_type)] + ) )[0] return share_type @api.depends( - 'share_ids', - 'share_ids.share_product_id', - 'share_ids.share_product_id.default_code', - 'share_ids.share_number', + "share_ids", + "share_ids.share_product_id", + "share_ids.share_product_id.default_code", + "share_ids.share_number", ) def _is_worker(self): """ @@ -53,7 +53,7 @@ class Partner(models.Model): rec.worker_store = False def _search_worker(self, operator, value): - return [('worker_store', operator, value)] + return [("worker_store", operator, value)] @api.depends( "cooperative_status_ids", @@ -79,10 +79,11 @@ class Partner(models.Model): else: rec.can_shop = ( rec.cooperative_status_ids.can_shop - if rec.is_worker and rec.cooperative_status_ids else False + if rec.is_worker and rec.cooperative_status_ids + else False ) - @api.constrains('parent_eater_id') + @api.constrains("parent_eater_id") def _check_max_parent_eaters(self): """ Check that the parent_eater_id in parnter in self doesn't exceed @@ -95,16 +96,15 @@ class Partner(models.Model): if ( share_type and share_type.max_nb_eater_allowed >= 0 - and len( - rec.parent_eater_id.child_eater_ids - ) > share_type.max_nb_eater_allowed + and len(rec.parent_eater_id.child_eater_ids) + > share_type.max_nb_eater_allowed ): raise ValidationError( - _('You can only set %d additional eaters per worker') + _("You can only set %d additional eaters per worker") % share_type.max_nb_eater_allowed ) - @api.constrains('child_eater_ids') + @api.constrains("child_eater_ids") def _check_max_child_eaters(self): """ Check the maximum number of eaters that can be assigned to a @@ -119,6 +119,6 @@ class Partner(models.Model): and len(rec.child_eater_ids) > share_type.max_nb_eater_allowed ): raise ValidationError( - _('You can only set %d additional eaters per worker') + _("You can only set %d additional eaters per worker") % share_type.max_nb_eater_allowed ) diff --git a/beesdoo_easy_my_coop/models/subscription_request.py b/beesdoo_easy_my_coop/models/subscription_request.py index 8c4b734..b701d87 100644 --- a/beesdoo_easy_my_coop/models/subscription_request.py +++ b/beesdoo_easy_my_coop/models/subscription_request.py @@ -1,26 +1,25 @@ # Copyright 2019 Coop IT Easy SCRLfs # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models class SubscriptionRequest(models.Model): - _inherit = 'subscription.request' + _inherit = "subscription.request" info_session_confirmed = fields.Boolean( - string="Confirmed Info Session", - default=False, + string="Confirmed Info Session", default=False ) def get_partner_vals(self): partner_vals = super(SubscriptionRequest, self).get_partner_vals() - partner_vals['info_session_confirmed'] = self.info_session_confirmed + partner_vals["info_session_confirmed"] = self.info_session_confirmed return partner_vals def get_required_field(self): required_fields = super(SubscriptionRequest, self).get_required_field() - company = self.env['res.company']._company_default_get() + company = self.env["res.company"]._company_default_get() if company.info_session_confirmation_required: - required_fields.append('info_session_confirmed') + required_fields.append("info_session_confirmed") return required_fields diff --git a/beesdoo_easy_my_coop/tests/test_res_partner.py b/beesdoo_easy_my_coop/tests/test_res_partner.py index 742c487..68ddbae 100644 --- a/beesdoo_easy_my_coop/tests/test_res_partner.py +++ b/beesdoo_easy_my_coop/tests/test_res_partner.py @@ -19,9 +19,7 @@ class TestResPartner(TransactionCase): Test adding eater to a cooperator and raise when max is reached. """ - coop1 = self.env.ref( - "beesdoo_base.res_partner_cooperator_1_demo" - ) + coop1 = self.env.ref("beesdoo_base.res_partner_cooperator_1_demo") coop1.write({"child_eater_ids": [(4, self.eater1.id)]}) self.assertEqual(len(coop1.child_eater_ids), 1) coop1.write({"child_eater_ids": [(4, self.eater2.id)]}) @@ -50,9 +48,7 @@ class TestResPartner(TransactionCase): Test adding eater to a cooperator and raise when max is reached. """ - coop2 = self.env.ref( - "beesdoo_base.res_partner_cooperator_2_demo" - ) + coop2 = self.env.ref("beesdoo_base.res_partner_cooperator_2_demo") coop2.write({"child_eater_ids": [(4, self.eater1.id)]}) self.assertEqual(len(coop2.child_eater_ids), 1) coop2.write({"child_eater_ids": [(4, self.eater2.id)]}) @@ -76,9 +72,7 @@ class TestResPartner(TransactionCase): """ Test that share_c can have an unlimited number of eater. """ - coop3 = self.env.ref( - "beesdoo_base.res_partner_cooperator_3_demo" - ) + coop3 = self.env.ref("beesdoo_base.res_partner_cooperator_3_demo") coop3.write({"child_eater_ids": [(4, self.eater1.id)]}) self.assertEqual(len(coop3.child_eater_ids), 1) coop3.write({"child_eater_ids": [(4, self.eater2.id)]}) @@ -94,9 +88,7 @@ class TestResPartner(TransactionCase): """ share_c = self.env.ref("beesdoo_easy_my_coop.share_c") share_c.max_nb_eater_allowed = 0 - coop3 = self.env.ref( - "beesdoo_base.res_partner_cooperator_3_demo" - ) + coop3 = self.env.ref("beesdoo_base.res_partner_cooperator_3_demo") with self.assertRaises(ValidationError) as econtext: coop3.write({"child_eater_ids": [(4, self.eater3.id)]}) self.assertIn("can only set", str(econtext.exception)) @@ -108,9 +100,7 @@ class TestResPartner(TransactionCase): """ Test adding multiple eater in one write. """ - coop1 = self.env.ref( - "beesdoo_base.res_partner_cooperator_1_demo" - ) + coop1 = self.env.ref("beesdoo_base.res_partner_cooperator_1_demo") coop1.write( { "child_eater_ids": [ @@ -126,9 +116,7 @@ class TestResPartner(TransactionCase): """ Test adding a parent to multiple eater in one write from the eater. """ - coop1 = self.env.ref( - "beesdoo_base.res_partner_cooperator_1_demo" - ) + coop1 = self.env.ref("beesdoo_base.res_partner_cooperator_1_demo") eaters = self.eater1 eaters |= self.eater2 eaters |= self.eater3 @@ -139,9 +127,7 @@ class TestResPartner(TransactionCase): """ Test that a cooperator is a worker based on his share type. """ - coop1 = self.env.ref( - "beesdoo_base.res_partner_cooperator_1_demo" - ) + coop1 = self.env.ref("beesdoo_base.res_partner_cooperator_1_demo") # Run computed field coop1._is_worker() self.assertEqual(coop1.is_worker, True) @@ -150,9 +136,7 @@ class TestResPartner(TransactionCase): """ Test that a cooperator is a worker based on his share type. """ - coop2 = self.env.ref( - "beesdoo_base.res_partner_cooperator_2_demo" - ) + coop2 = self.env.ref("beesdoo_base.res_partner_cooperator_2_demo") # Run computed field coop2._is_worker() self.assertEqual(coop2.is_worker, False) @@ -162,12 +146,8 @@ class TestResPartner(TransactionCase): Test that the search function returns worker based on the 'is_worker' field. """ - coop1 = self.env.ref( - "beesdoo_base.res_partner_cooperator_1_demo" - ) - coop2 = self.env.ref( - "beesdoo_base.res_partner_cooperator_2_demo" - ) + coop1 = self.env.ref("beesdoo_base.res_partner_cooperator_1_demo") + coop2 = self.env.ref("beesdoo_base.res_partner_cooperator_2_demo") # Run computed field coop1._is_worker() coop2._is_worker() @@ -182,14 +162,12 @@ class TestResPartner(TransactionCase): """ Test that a cooperator can shop based on his share type. """ - coop1 = self.env.ref( - "beesdoo_base.res_partner_cooperator_1_demo" - ) + coop1 = self.env.ref("beesdoo_base.res_partner_cooperator_1_demo") # Run computed field coop1._compute_can_shop() self.assertEqual(coop1.can_shop, True) # Now unsubscribe the coop - coop1.cooperative_status_ids.status = 'resigning' + coop1.cooperative_status_ids.status = "resigning" self.assertEqual(coop1.cooperative_status_ids.can_shop, False) self.assertEqual(coop1.can_shop, False) @@ -197,9 +175,7 @@ class TestResPartner(TransactionCase): """ Test that a cooperator can shop based on his share type. """ - coop3 = self.env.ref( - "beesdoo_base.res_partner_cooperator_3_demo" - ) + coop3 = self.env.ref("beesdoo_base.res_partner_cooperator_3_demo") # Run computed field coop3._compute_can_shop() self.assertEqual(coop3.can_shop, False) diff --git a/beesdoo_easy_my_coop/wizards/beesdoo_shift_subscribe.py b/beesdoo_easy_my_coop/wizards/beesdoo_shift_subscribe.py index 7cc79f5..6fea98d 100644 --- a/beesdoo_easy_my_coop/wizards/beesdoo_shift_subscribe.py +++ b/beesdoo_easy_my_coop/wizards/beesdoo_shift_subscribe.py @@ -1,12 +1,12 @@ # Copyright 2019 Coop IT Easy SCRLfs # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models class Subscribe(models.TransientModel): - _inherit = 'beesdoo.shift.subscribe' + _inherit = "beesdoo.shift.subscribe" def _get_info_session_followed(self): """ @@ -15,10 +15,11 @@ class Subscribe(models.TransientModel): """ followed = super(Subscribe, self)._get_info_session_followed() if not followed: - return (self.env['res.partner'] - .browse(self._context.get('active_id')) - .info_session_confirmed) + return ( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .info_session_confirmed + ) return followed info_session = fields.Boolean(default=_get_info_session_followed) - diff --git a/beesdoo_inventory/__manifest__.py b/beesdoo_inventory/__manifest__.py index 1f68355..98874a3 100644 --- a/beesdoo_inventory/__manifest__.py +++ b/beesdoo_inventory/__manifest__.py @@ -5,23 +5,18 @@ # - Jean-Marc François # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': "Beesdoo Inventory", - - 'summary': """ + "name": "Beesdoo Inventory", + "summary": """ Adds a responsible, a max shipping date and a button to copy quantity to stock pickings.""", - - 'description': """ + "description": """ """, - - 'author': "Beescoop - Cellule IT", - 'website': "https://github.com/beescoop/Obeesdoo", - 'category': 'Inventory', - 'version': '12.0.1.0.0', - 'depends': ['delivery', 'beesdoo_base', 'beesdoo_product'], - 'data': [ - 'views/stock.xml' - ], - 'installable': True, + "author": "Beescoop - Cellule IT", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Inventory", + "version": "12.0.1.0.0", + "depends": ["delivery", "beesdoo_base", "beesdoo_product"], + "data": ["views/stock.xml"], + "installable": True, } diff --git a/beesdoo_inventory/models/stock.py b/beesdoo_inventory/models/stock.py index fe56402..7b5d8b9 100644 --- a/beesdoo_inventory/models/stock.py +++ b/beesdoo_inventory/models/stock.py @@ -1,21 +1,40 @@ -from odoo import _, api, fields, models +from odoo import _, api, fields, models + class StockPicking(models.Model): - _inherit = 'stock.picking' + _inherit = "stock.picking" max_shipping_date = fields.Datetime("End Shipping Date") - responsible = fields.Many2one('res.partner', string="Responsible", default=lambda self: self.env.user.partner_id.id) + responsible = fields.Many2one( + "res.partner", + string="Responsible", + default=lambda self: self.env.user.partner_id.id, + ) def _add_follower(self): - if(self.responsible): - types = self.env['mail.message.subtype'].search(['|',('res_model','=','stock.picking'),('name','=','Discussions')]) - if not self.env['mail.followers'].search([('res_id', '=', self.id), - ('res_model', '=', 'stock.picking'), - ('partner_id', '=', self.responsible.id)]): - self.env['mail.followers'].create({'res_model' : 'stock.picking', - 'res_id' : self.id, - 'partner_id' : self.responsible.id, - 'subtype_ids': [(6, 0, types.ids)]}) + if self.responsible: + types = self.env["mail.message.subtype"].search( + [ + "|", + ("res_model", "=", "stock.picking"), + ("name", "=", "Discussions"), + ] + ) + if not self.env["mail.followers"].search( + [ + ("res_id", "=", self.id), + ("res_model", "=", "stock.picking"), + ("partner_id", "=", self.responsible.id), + ] + ): + self.env["mail.followers"].create( + { + "res_model": "stock.picking", + "res_id": self.id, + "partner_id": self.responsible.id, + "subtype_ids": [(6, 0, types.ids)], + } + ) @api.multi def write(self, values): diff --git a/beesdoo_inventory/readme/CONTRIBUTORS.rst b/beesdoo_inventory/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_inventory/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_pos/__init__.py b/beesdoo_pos/__init__.py index 9a7e03e..0650744 100644 --- a/beesdoo_pos/__init__.py +++ b/beesdoo_pos/__init__.py @@ -1 +1 @@ -from . import models \ No newline at end of file +from . import models diff --git a/beesdoo_pos/__manifest__.py b/beesdoo_pos/__manifest__.py index 8483f81..d5b88fb 100644 --- a/beesdoo_pos/__manifest__.py +++ b/beesdoo_pos/__manifest__.py @@ -6,29 +6,19 @@ # - Grégoire Leeuwerck # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': "Beescoop Point of sale", - - 'summary': """ + "name": "Beescoop Point of sale", + "summary": """ Module that extends the pos for the beescoop """, - - 'description': """ + "description": """ This module adds the eaters of the customer to the POS ActionpadWidget and PaymentScreenWidget. """, - - 'author': "Beescoop - Cellule IT", - 'website': "https://github.com/beescoop/Obeesdoo", - - 'category': 'Point Of Sale', - 'version': '12.0.1.0.0', - - 'depends': ['beesdoo_base', 'beesdoo_product'], - - 'data': [ - 'views/beesdoo_pos.xml', - 'data/default_barcode_pattern.xml', - ], - 'qweb': ['static/src/xml/templates.xml'], - - 'installable': True, + "author": "Beescoop - Cellule IT", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Point Of Sale", + "version": "12.0.1.0.0", + "depends": ["beesdoo_base", "beesdoo_product"], + "data": ["views/beesdoo_pos.xml", "data/default_barcode_pattern.xml",], + "qweb": ["static/src/xml/templates.xml"], + "installable": True, } diff --git a/beesdoo_pos/models/__init__.py b/beesdoo_pos/models/__init__.py index 4105a69..09371b2 100644 --- a/beesdoo_pos/models/__init__.py +++ b/beesdoo_pos/models/__init__.py @@ -1 +1 @@ -from . import beesdoo_pos \ No newline at end of file +from . import beesdoo_pos diff --git a/beesdoo_pos/models/beesdoo_pos.py b/beesdoo_pos/models/beesdoo_pos.py index b08301b..5f6e839 100644 --- a/beesdoo_pos/models/beesdoo_pos.py +++ b/beesdoo_pos/models/beesdoo_pos.py @@ -1,8 +1,8 @@ -from odoo import models, api +from odoo import api, models class BeescoopPosPartner(models.Model): - _inherit = 'res.partner' + _inherit = "res.partner" def _get_eater(self): eaters = [False, False, False] diff --git a/beesdoo_pos/readme/CONTRIBUTORS.rst b/beesdoo_pos/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_pos/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_pos/static/src/css/beesdoo.css b/beesdoo_pos/static/src/css/beesdoo.css index 66180cd..1ff6a61 100644 --- a/beesdoo_pos/static/src/css/beesdoo.css +++ b/beesdoo_pos/static/src/css/beesdoo.css @@ -31,4 +31,4 @@ .pos .actionpad .button.pay { height: 108px; -} \ No newline at end of file +} diff --git a/beesdoo_pos_reporting/models/res_partner.py b/beesdoo_pos_reporting/models/res_partner.py index b74a24e..64f2e98 100644 --- a/beesdoo_pos_reporting/models/res_partner.py +++ b/beesdoo_pos_reporting/models/res_partner.py @@ -4,4 +4,4 @@ from odoo import fields, models class ResPartner(models.Model): _inherit = "res.partner" - pos_order_count = fields.Integer(store=True,) + pos_order_count = fields.Integer(store=True) diff --git a/beesdoo_pos_reporting/readme/CONTRIBUTORS.rst b/beesdoo_pos_reporting/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_pos_reporting/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_product/__manifest__.py b/beesdoo_product/__manifest__.py index a76a01f..576736f 100644 --- a/beesdoo_product/__manifest__.py +++ b/beesdoo_product/__manifest__.py @@ -6,30 +6,26 @@ # - Thibault François # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': "beesdoo_product", - - 'summary': """ + "name": "beesdoo_product", + "summary": """ Modification of product module for the needs of beescoop - SOOO5 - Ajout de label bio/ethique/provenance""", - - 'description': """ + "description": """ """, - - 'author': "Beescoop - Cellule IT", - 'website': "https://github.com/beescoop/Obeesdoo", - 'category': 'Sales', - 'version': '12.0.1.0.0', - 'depends': ['beesdoo_base', 'product', 'sale', 'point_of_sale'], - - 'data': [ - 'data/product_label.xml', - 'data/barcode_rule.xml', - 'data/product_sequence.xml', - 'views/beesdoo_product.xml', - 'views/assets.xml', - 'wizard/views/label_printing_utils.xml', - 'security/ir.model.access.csv', + "author": "Beescoop - Cellule IT", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Sales", + "version": "12.0.1.0.0", + "depends": ["beesdoo_base", "product", "sale", "point_of_sale"], + "data": [ + "data/product_label.xml", + "data/barcode_rule.xml", + "data/product_sequence.xml", + "views/beesdoo_product.xml", + "views/assets.xml", + "wizard/views/label_printing_utils.xml", + "security/ir.model.access.csv", ], - 'installable': True, + "installable": True, } diff --git a/beesdoo_product/data/product_sequence.xml b/beesdoo_product/data/product_sequence.xml index d1b2748..f924376 100644 --- a/beesdoo_product/data/product_sequence.xml +++ b/beesdoo_product/data/product_sequence.xml @@ -1,14 +1,14 @@ - - - - - Internal reference - product.internal.code - - 5 - - 1 - - - - \ No newline at end of file + + + + + Internal reference + product.internal.code + + 5 + + 1 + + + + diff --git a/beesdoo_product/models/__init__.py b/beesdoo_product/models/__init__.py index 52cfd16..0494b5e 100644 --- a/beesdoo_product/models/__init__.py +++ b/beesdoo_product/models/__init__.py @@ -1 +1 @@ -from . import beesdoo_product \ No newline at end of file +from . import beesdoo_product diff --git a/beesdoo_product/models/beesdoo_product.py b/beesdoo_product/models/beesdoo_product.py index ff9d231..9f47dc2 100644 --- a/beesdoo_product/models/beesdoo_product.py +++ b/beesdoo_product/models/beesdoo_product.py @@ -1,59 +1,93 @@ import uuid -from odoo import models, fields, api -from odoo.tools.translate import _ +from odoo import api, fields, models from odoo.exceptions import UserError, ValidationError +from odoo.tools.translate import _ class BeesdooProduct(models.Model): _inherit = "product.template" - eco_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'eco')]) - local_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'local')]) - fair_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'fair')]) - origin_label = fields.Many2one('beesdoo.product.label', domain=[('type', '=', 'delivery')]) + eco_label = fields.Many2one( + "beesdoo.product.label", domain=[("type", "=", "eco")] + ) + local_label = fields.Many2one( + "beesdoo.product.label", domain=[("type", "=", "local")] + ) + fair_label = fields.Many2one( + "beesdoo.product.label", domain=[("type", "=", "fair")] + ) + origin_label = fields.Many2one( + "beesdoo.product.label", domain=[("type", "=", "delivery")] + ) - main_seller_id = fields.Many2one('res.partner', string='Main Seller', compute='_compute_main_seller_id', store=True) + main_seller_id = fields.Many2one( + "res.partner", + string="Main Seller", + compute="_compute_main_seller_id", + store=True, + ) - display_unit = fields.Many2one('uom.uom') - default_reference_unit = fields.Many2one('uom.uom') - display_weight = fields.Float(compute='_get_display_weight', store=True) + display_unit = fields.Many2one("uom.uom") + default_reference_unit = fields.Many2one("uom.uom") + display_weight = fields.Float(compute="_get_display_weight", store=True) - total_with_vat = fields.Float(compute='_get_total', store=True, string="Total Sales Price with VAT") - total_with_vat_by_unit = fields.Float(compute='_get_total', store=True, string="Total Sales Price with VAT by Reference Unit") - total_deposit = fields.Float(compute='_get_total', store=True, string="Deposit Price") + total_with_vat = fields.Float( + compute="_get_total", store=True, string="Total Sales Price with VAT" + ) + total_with_vat_by_unit = fields.Float( + compute="_get_total", + store=True, + string="Total Sales Price with VAT by Reference Unit", + ) + total_deposit = fields.Float( + compute="_get_total", store=True, string="Deposit Price" + ) - label_to_be_printed = fields.Boolean('Print label?') - label_last_printed = fields.Datetime('Label last printed on') + label_to_be_printed = fields.Boolean("Print label?") + label_last_printed = fields.Datetime("Label last printed on") + + note = fields.Text("Comments") - note = fields.Text('Comments') - # S0023 : List_price = Price HTVA, so add a suggested price - list_price = fields.Float(string='exVAT Price') - suggested_price = fields.Float(string='Suggested exVAT Price', compute='_compute_cost', readOnly=True) - + list_price = fields.Float(string="exVAT Price") + suggested_price = fields.Float( + string="Suggested exVAT Price", compute="_compute_cost", readOnly=True + ) + deadline_for_sale = fields.Integer(string="Deadline for sale(days)") - deadline_for_consumption = fields.Integer(string="Deadline for consumption(days)") + deadline_for_consumption = fields.Integer( + string="Deadline for consumption(days)" + ) ingredients = fields.Char(string="Ingredient") scale_label_info_1 = fields.Char(string="Scale lable info 1") scale_label_info_2 = fields.Char(string="Scale lable info 2") - scale_sale_unit = fields.Char(compute="_get_scale_sale_uom", string="Scale sale unit", store=True) - scale_category = fields.Many2one('beesdoo.scale.category', string="Scale Category") - scale_category_code = fields.Integer(related='scale_category.code', string="Scale category code", readonly=True, store=True) - - @api.depends('uom_id','uom_id.category_id','uom_id.category_id.type') + scale_sale_unit = fields.Char( + compute="_get_scale_sale_uom", string="Scale sale unit", store=True + ) + scale_category = fields.Many2one( + "beesdoo.scale.category", string="Scale Category" + ) + scale_category_code = fields.Integer( + related="scale_category.code", + string="Scale category code", + readonly=True, + store=True, + ) + + @api.depends("uom_id", "uom_id.category_id", "uom_id.category_id.type") @api.multi def _get_scale_sale_uom(self): for product in self: - if product.uom_id.category_id.type == 'unit': - product.scale_sale_unit = 'F' - elif product.uom_id.category_id.type == 'weight': - product.scale_sale_unit = 'P' - + if product.uom_id.category_id.type == "unit": + product.scale_sale_unit = "F" + elif product.uom_id.category_id.type == "weight": + product.scale_sale_unit = "P" + def _get_main_supplier_info(self): suppliers = self.seller_ids.sorted( - key=lambda seller: seller.date_start, - reverse=True) + key=lambda seller: seller.date_start, reverse=True + ) if suppliers: return suppliers[0] else: @@ -62,84 +96,140 @@ class BeesdooProduct(models.Model): @api.one def generate_barcode(self): if self.to_weight: - seq_internal_code = self.env.ref('beesdoo_product.seq_ean_product_internal_ref') - bc = '' + seq_internal_code = self.env.ref( + "beesdoo_product.seq_ean_product_internal_ref" + ) + bc = "" if not self.default_code: - rule = self.env['barcode.rule'].search([('name', '=', 'Price Barcodes (Computed Weight) 2 Decimals')])[0] + rule = self.env["barcode.rule"].search( + [ + ( + "name", + "=", + "Price Barcodes (Computed Weight) 2 Decimals", + ) + ] + )[0] default_code = seq_internal_code.next_by_id() - while(self.search_count([('default_code', '=', default_code)]) > 1): + while ( + self.search_count([("default_code", "=", default_code)]) + > 1 + ): default_code = seq_internal_code.next_by_id() self.default_code = default_code - ean = '02' + self.default_code[0:5] + '000000' - bc = ean[0:12] + str(self.env['barcode.nomenclature'].ean_checksum(ean)) + ean = "02" + self.default_code[0:5] + "000000" + bc = ean[0:12] + str( + self.env["barcode.nomenclature"].ean_checksum(ean) + ) else: - rule = self.env['barcode.rule'].search([('name', '=', 'Beescoop Product Barcodes')])[0] + rule = self.env["barcode.rule"].search( + [("name", "=", "Beescoop Product Barcodes")] + )[0] size = 13 - len(rule.pattern) ean = rule.pattern + str(uuid.uuid4().fields[-1])[:size] - bc = ean[0:12] + str(self.env['barcode.nomenclature'].ean_checksum(ean)) + bc = ean[0:12] + str( + self.env["barcode.nomenclature"].ean_checksum(ean) + ) # Make sure there is no other active member with the same barcode - while(self.search_count([('barcode', '=', bc)]) > 1): + while self.search_count([("barcode", "=", bc)]) > 1: ean = rule.pattern + str(uuid.uuid4().fields[-1])[:size] - bc = ean[0:12] + str(self.env['barcode.nomenclature'].ean_checksum(ean)) - print('barcode :', bc) + bc = ean[0:12] + str( + self.env["barcode.nomenclature"].ean_checksum(ean) + ) + print("barcode :", bc) self.barcode = bc @api.one - @api.depends('seller_ids', 'seller_ids.date_start') + @api.depends("seller_ids", "seller_ids.date_start") def _compute_main_seller_id(self): # Calcule le vendeur associé qui a la date de début la plus récente et plus petite qu’aujourd’hui - sellers_ids = self._get_main_supplier_info() # self.seller_ids.sorted(key=lambda seller: seller.date_start, reverse=True) + sellers_ids = ( + self._get_main_supplier_info() + ) # self.seller_ids.sorted(key=lambda seller: seller.date_start, reverse=True) self.main_seller_id = sellers_ids and sellers_ids[0].name or False @api.one - @api.depends('taxes_id', 'list_price', 'taxes_id.amount', - 'taxes_id.tax_group_id', - 'display_weight', 'weight') + @api.depends( + "taxes_id", + "list_price", + "taxes_id.amount", + "taxes_id.tax_group_id", + "display_weight", + "weight", + ) def _get_total(self): - consignes_group = self.env.ref('beesdoo_product.consignes_group_tax', - raise_if_not_found=False) + consignes_group = self.env.ref( + "beesdoo_product.consignes_group_tax", raise_if_not_found=False + ) - taxes_included = set(self.taxes_id.mapped('price_include')) + taxes_included = set(self.taxes_id.mapped("price_include")) if len(taxes_included) == 0: self.total_with_vat = self.list_price return True elif len(taxes_included) > 1: - raise ValidationError('Several tax strategies (price_include) defined for %s' % self.name) + raise ValidationError( + "Several tax strategies (price_include) defined for %s" + % self.name + ) elif taxes_included.pop(): self.total_with_vat = self.list_price - self.total_deposit = sum([tax._compute_amount(self.list_price, self.list_price) for tax in self.taxes_id if tax.tax_group_id == consignes_group]) + self.total_deposit = sum( + [ + tax._compute_amount(self.list_price, self.list_price) + for tax in self.taxes_id + if tax.tax_group_id == consignes_group + ] + ) else: - tax_amount_sum = sum([tax._compute_amount(self.list_price, self.list_price) - for tax in self.taxes_id - if tax.tax_group_id != consignes_group]) + tax_amount_sum = sum( + [ + tax._compute_amount(self.list_price, self.list_price) + for tax in self.taxes_id + if tax.tax_group_id != consignes_group + ] + ) self.total_with_vat = self.list_price + tax_amount_sum - self.total_deposit = sum([tax._compute_amount(self.list_price, self.list_price) - for tax in self.taxes_id - if tax.tax_group_id == consignes_group]) + self.total_deposit = sum( + [ + tax._compute_amount(self.list_price, self.list_price) + for tax in self.taxes_id + if tax.tax_group_id == consignes_group + ] + ) if self.display_weight > 0: self.total_with_vat_by_unit = self.total_with_vat / self.weight @api.one - @api.depends('weight', 'display_unit') + @api.depends("weight", "display_unit") def _get_display_weight(self): self.display_weight = self.weight * self.display_unit.factor @api.one - @api.constrains('display_unit', 'default_reference_unit') + @api.constrains("display_unit", "default_reference_unit") def _unit_same_category(self): - if self.display_unit.category_id != self.default_reference_unit.category_id: - raise UserError(_('Reference Unit and Display Unit should belong to the same category')) + if ( + self.display_unit.category_id + != self.default_reference_unit.category_id + ): + raise UserError( + _( + "Reference Unit and Display Unit should belong to the same category" + ) + ) @api.one - @api.depends('seller_ids') + @api.depends("seller_ids") def _compute_cost(self): suppliers = self._get_main_supplier_info() - if(len(suppliers) > 0): - self.suggested_price = (suppliers[0].price * self.uom_po_id.factor)* (1 + suppliers[0].product_tmpl_id.categ_id.profit_margin / 100) + if len(suppliers) > 0: + self.suggested_price = ( + suppliers[0].price * self.uom_po_id.factor + ) * (1 + suppliers[0].product_tmpl_id.categ_id.profit_margin / 100) + class BeesdooScaleCategory(models.Model): _name = "beesdoo.scale.category" @@ -147,43 +237,64 @@ class BeesdooScaleCategory(models.Model): name = fields.Char(string="Scale name category") code = fields.Integer(string="Category code") - + _sql_constraints = [ - ('code_scale_categ_uniq', 'unique (code)', 'The code of the scale category must be unique !') + ( + "code_scale_categ_uniq", + "unique (code)", + "The code of the scale category must be unique !", + ) ] - + + class BeesdooProductLabel(models.Model): _name = "beesdoo.product.label" _description = "beesdoo.product.label" name = fields.Char() - type = fields.Selection([('eco', 'Écologique'), ('local', 'Local'), ('fair', 'Équitable'), ('delivery', 'Distribution')]) + type = fields.Selection( + [ + ("eco", "Écologique"), + ("local", "Local"), + ("fair", "Équitable"), + ("delivery", "Distribution"), + ] + ) color_code = fields.Char() active = fields.Boolean(default=True) + class BeesdooProductCategory(models.Model): _inherit = "product.category" - profit_margin = fields.Float(default = '10.0', string = "Product Margin [%]") + profit_margin = fields.Float(default="10.0", string="Product Margin [%]") @api.one - @api.constrains('profit_margin') + @api.constrains("profit_margin") def _check_margin(self): - if (self.profit_margin < 0.0): - raise UserError(_('Percentages for Profit Margin must > 0.')) + if self.profit_margin < 0.0: + raise UserError(_("Percentages for Profit Margin must > 0.")) + class BeesdooProductSupplierInfo(models.Model): _inherit = "product.supplierinfo" - price = fields.Float('exVAT Price') + price = fields.Float("exVAT Price") + class BeesdooUOMCateg(models.Model): - _inherit = 'uom.category' - - type = fields.Selection([('unit','Unit'), - ('weight','Weight'), - ('time','Time'), - ('distance','Distance'), - ('surface','Surface'), - ('volume','Volume'), - ('other','Other')],string='Category type',default='unit') + _inherit = "uom.category" + + type = fields.Selection( + [ + ("unit", "Unit"), + ("weight", "Weight"), + ("time", "Time"), + ("distance", "Distance"), + ("surface", "Surface"), + ("volume", "Volume"), + ("other", "Other"), + ], + string="Category type", + default="unit", + ) diff --git a/beesdoo_product/readme/CONTRIBUTORS.rst b/beesdoo_product/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_product/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_product/security/ir.model.access.csv b/beesdoo_product/security/ir.model.access.csv index 765d2d3..4a60e01 100644 --- a/beesdoo_product/security/ir.model.access.csv +++ b/beesdoo_product/security/ir.model.access.csv @@ -1,5 +1,5 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -beesdoo_product_label_read_all,beesdoo.product.label Read All,model_beesdoo_product_label,,1,0,0,0 -beesdoo_product_label_all_access_sale_manager,beesdoo.product.label All Access Sale Manager,model_beesdoo_product_label,sales_team.group_sale_manager,1,1,1,1 -beesdoo_scale_category_read_all,beesdoo.scale.category Read All,model_beesdoo_scale_category,,1,0,0,0 -beesdoo_scale_categoryl_all_access_sale_manager,beesdoo.scale.category All Access Sale Manager,model_beesdoo_scale_category,sales_team.group_sale_manager,1,1,1,0 +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +beesdoo_product_label_read_all,beesdoo.product.label Read All,model_beesdoo_product_label,,1,0,0,0 +beesdoo_product_label_all_access_sale_manager,beesdoo.product.label All Access Sale Manager,model_beesdoo_product_label,sales_team.group_sale_manager,1,1,1,1 +beesdoo_scale_category_read_all,beesdoo.scale.category Read All,model_beesdoo_scale_category,,1,0,0,0 +beesdoo_scale_categoryl_all_access_sale_manager,beesdoo.scale.category All Access Sale Manager,model_beesdoo_scale_category,sales_team.group_sale_manager,1,1,1,0 diff --git a/beesdoo_product/wizard/label_printing_utils.py b/beesdoo_product/wizard/label_printing_utils.py index d2e466b..93fb06b 100644 --- a/beesdoo_product/wizard/label_printing_utils.py +++ b/beesdoo_product/wizard/label_printing_utils.py @@ -1,20 +1,26 @@ -from odoo import models, fields, api +from odoo import api, fields, models + class RequestLabelPrintingWizard(models.TransientModel): - _name = 'label.printing.wizard' - _description = 'label.printing.wizard' + _name = "label.printing.wizard" + _description = "label.printing.wizard" def _get_selected_products(self): - return self.env.context['active_ids'] - - product_ids = fields.Many2many('product.template', default=_get_selected_products) + return self.env.context["active_ids"] + product_ids = fields.Many2many( + "product.template", default=_get_selected_products + ) @api.one def request_printing(self): - self.product_ids.write({'label_to_be_printed' : True}) - + self.product_ids.write({"label_to_be_printed": True}) @api.one def set_as_printed(self): - self.product_ids.write({'label_to_be_printed' : False, 'label_last_printed' : fields.Datetime.now()}) + self.product_ids.write( + { + "label_to_be_printed": False, + "label_last_printed": fields.Datetime.now(), + } + ) diff --git a/beesdoo_product_usability/__manifest__.py b/beesdoo_product_usability/__manifest__.py index 8709982..4954305 100644 --- a/beesdoo_product_usability/__manifest__.py +++ b/beesdoo_product_usability/__manifest__.py @@ -1,22 +1,18 @@ # Copyright 2017 - 2020 BEES coop SCRLfs # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': "BEES coop Product Usability", - - 'description': """ - Adapt the + "name": "BEES coop Product Usability", + "summary": """ + Adapt the product views. """, - - 'author': "Beescoop - Cellule IT, Coop IT Easy", - 'website': "https://github.com/beescoop/Obeesdoo", - 'category': 'Sales Management', - 'version': '12.0.1.0.0', - 'depends': [ - 'beesdoo_product', - 'beesdoo_stock_coverage', - 'beesdoo_purchase', - ], - 'data': [ - 'views/beesdoo_product.xml', + "author": "Beescoop - Cellule IT, Coop IT Easy SCRLfs", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Sales Management", + "version": "12.0.1.0.0", + "depends": [ + "beesdoo_product", + "beesdoo_stock_coverage", + "beesdoo_purchase", ], + "data": ["views/beesdoo_product.xml",], } diff --git a/beesdoo_product_usability/models/beesdoo_product.py b/beesdoo_product_usability/models/beesdoo_product.py index 884483b..4c651a3 100644 --- a/beesdoo_product_usability/models/beesdoo_product.py +++ b/beesdoo_product_usability/models/beesdoo_product.py @@ -1,25 +1,23 @@ -from odoo import models, fields, api +from odoo import api, fields, models class BeesdooProduct(models.Model): _inherit = "product.template" main_supplierinfo = fields.Many2one( - 'product.supplierinfo', - string='Main Supplier Information', - compute='_compute_main_supplierinfo' + "product.supplierinfo", + string="Main Supplier Information", + compute="_compute_main_supplierinfo", ) main_price = fields.Float( - string='Price', - compute='_compute_main_supplierinfo', + string="Price", compute="_compute_main_supplierinfo" ) main_minimum_qty = fields.Float( - string='Minimum Quantity', - compute='_compute_main_supplierinfo', + string="Minimum Quantity", compute="_compute_main_supplierinfo" ) @api.multi - @api.depends('seller_ids') + @api.depends("seller_ids") def _compute_main_supplierinfo(self): for product in self: supplierinfo = product._get_main_supplier_info() diff --git a/beesdoo_purchase/__manifest__.py b/beesdoo_purchase/__manifest__.py index 938e3c1..b8dbb48 100644 --- a/beesdoo_purchase/__manifest__.py +++ b/beesdoo_purchase/__manifest__.py @@ -18,8 +18,5 @@ "category": "Purchase", "version": "12.0.1.1.0", "depends": ["base", "purchase", "beesdoo_product"], - "data": [ - "views/purchase_order.xml", - "report/report_purchaseorder.xml", - ], + "data": ["views/purchase_order.xml", "report/report_purchaseorder.xml",], } diff --git a/beesdoo_shift/__manifest__.py b/beesdoo_shift/__manifest__.py index 08db04f..4891a4d 100644 --- a/beesdoo_shift/__manifest__.py +++ b/beesdoo_shift/__manifest__.py @@ -1,24 +1,18 @@ -{ - 'name': "Beescoop Shift Management", - - 'summary': """ - Volonteer Timetable Management""", - - 'description': """ - - """, +# Copyright 2020 Coop IT Easy SCRL fs +# Elouan Le Bars +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - 'author': "THibault Francois, Elouan Le Bars, Coop It Easy", - 'website': "https://github.com/beescoop/Obeesdoo", - 'category': 'Cooperative management', - 'version': '12.0.1.0.0', - - 'depends': [ - 'mail', - ], - - 'data': [ +{ + "name": "Beescoop Shift Management", + "summary": """ + Volonteer Timetable Management""", + "author": "THibault Francois, Elouan Le Bars, Coop It Easy", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Cooperative management", + "version": "12.0.1.0.0", + "depends": ["mail",], + "data": [ "data/system_parameter.xml", "data/cron.xml", "data/mail_template.xml", @@ -38,8 +32,6 @@ "wizard/holiday.xml", "wizard/temporary_exemption.xml", ], - 'demo': [ - "demo/templates.xml", - "demo/workers.xml", - ] + "demo": ["demo/templates.xml", "demo/workers.xml",], + "license": "AGPL-3", } diff --git a/beesdoo_shift/models/__init__.py b/beesdoo_shift/models/__init__.py index 7b98f32..a06e5b1 100644 --- a/beesdoo_shift/models/__init__.py +++ b/beesdoo_shift/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from . import task from . import planning from . import cooperative_status diff --git a/beesdoo_shift/models/cooperative_status.py b/beesdoo_shift/models/cooperative_status.py index eb132c8..f33d946 100644 --- a/beesdoo_shift/models/cooperative_status.py +++ b/beesdoo_shift/models/cooperative_status.py @@ -1,149 +1,210 @@ -from odoo import models, fields, api, _ -from odoo.exceptions import ValidationError, UserError - -from datetime import timedelta, datetime import logging +from datetime import datetime, timedelta + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError _logger = logging.getLogger(__name__) + def add_days_delta(date_from, days_delta): if not date_from: return date_from next_date = date_from + timedelta(days=days_delta) return next_date + class ExemptReason(models.Model): - _name = 'cooperative.exempt.reason' - _description = 'cooperative.exempt.reason' + _name = "cooperative.exempt.reason" + _description = "cooperative.exempt.reason" name = fields.Char(required=True) + class HistoryStatus(models.Model): - _name = 'cooperative.status.history' - _description = 'cooperative.status.history' + _name = "cooperative.status.history" + _description = "cooperative.status.history" - _order= 'create_date desc' + _order = "create_date desc" - status_id = fields.Many2one('cooperative.status') - cooperator_id = fields.Many2one('res.partner') + status_id = fields.Many2one("cooperative.status") + cooperator_id = fields.Many2one("res.partner") change = fields.Char() - type = fields.Selection([('status', 'Status Change'), ('counter', 'Counter Change')]) - user_id = fields.Many2one('res.users', string="User") + type = fields.Selection( + [("status", "Status Change"), ("counter", "Counter Change")] + ) + user_id = fields.Many2one("res.users", string="User") + class CooperativeStatus(models.Model): - _name = 'cooperative.status' - _description = 'cooperative.status' - _rec_name = 'cooperator_id' - _order = 'cooperator_id' + _name = "cooperative.status" + _description = "cooperative.status" + _rec_name = "cooperator_id" + _order = "cooperator_id" _period = 28 def _get_status(self): return [ - ('ok', 'Up to Date'), - ('holiday', 'Holidays'), - ('alert', 'Alerte'), - ('extension', 'Extension'), - ('suspended', 'Suspended'), - ('exempted', 'Exempted'), - ('unsubscribed', 'Unsubscribed'), - ('resigning', 'Resigning') + ("ok", "Up to Date"), + ("holiday", "Holidays"), + ("alert", "Alerte"), + ("extension", "Extension"), + ("suspended", "Suspended"), + ("exempted", "Exempted"), + ("unsubscribed", "Unsubscribed"), + ("resigning", "Resigning"), ] - today = fields.Date(help="Field that allow to compute field and store them even if they are based on the current date", default=fields.Date.today) - cooperator_id = fields.Many2one('res.partner') - active = fields.Boolean(related="cooperator_id.active", store=True, index=True) - info_session = fields.Boolean('Information Session ?') - info_session_date = fields.Date('Information Session Date') + today = fields.Date( + help="Field that allow to compute field and store them even if they are based on the current date", + default=fields.Date.today, + ) + cooperator_id = fields.Many2one("res.partner") + active = fields.Boolean( + related="cooperator_id.active", store=True, index=True + ) + info_session = fields.Boolean("Information Session ?") + info_session_date = fields.Date("Information Session Date") super = fields.Boolean("Super Cooperative") sr = fields.Integer("Regular shifts counter", default=0) sc = fields.Integer("Compensation shifts counter", default=0) - time_extension = fields.Integer("Extension Days NB", default=0, help="Addtional days to the automatic extension, 5 mean that you have a total of 15 extension days of default one is set to 10") + time_extension = fields.Integer( + "Extension Days NB", + default=0, + help="Addtional days to the automatic extension, 5 mean that you have a total of 15 extension days of default one is set to 10", + ) holiday_start_time = fields.Date("Holidays Start Day") holiday_end_time = fields.Date("Holidays End Day") alert_start_time = fields.Date("Alert Start Day") extension_start_time = fields.Date("Extension Start Day") working_mode = fields.Selection( [ - ('regular', 'Regular worker'), - ('irregular', 'Irregular worker'), - ('exempt', 'Exempted'), + ("regular", "Regular worker"), + ("irregular", "Irregular worker"), + ("exempt", "Exempted"), ], - string="Working mode" + string="Working mode", + ) + exempt_reason_id = fields.Many2one( + "cooperative.exempt.reason", "Exempt Reason" + ) + status = fields.Selection( + selection=_get_status, + compute="_compute_status", + string="Cooperative Status", + store=True, + ) + can_shop = fields.Boolean(compute="_compute_can_shop", store=True) + history_ids = fields.One2many( + "cooperative.status.history", "status_id", readonly=True ) - exempt_reason_id = fields.Many2one('cooperative.exempt.reason', 'Exempt Reason') - status = fields.Selection(selection=_get_status, - compute="_compute_status", string="Cooperative Status", store=True) - can_shop = fields.Boolean(compute='_compute_can_shop', store=True) - history_ids = fields.One2many('cooperative.status.history', 'status_id', readonly=True) unsubscribed = fields.Boolean(default=False, help="Manually unsubscribed") - resigning = fields.Boolean(default=False, help="Want to leave the beescoop") + resigning = fields.Boolean( + default=False, help="Want to leave the beescoop" + ) - #Specific to irregular - irregular_start_date = fields.Date() #TODO migration script + # Specific to irregular + irregular_start_date = fields.Date() # TODO migration script irregular_absence_date = fields.Date() - irregular_absence_counter = fields.Integer() #TODO unsubscribe when reach -2 - future_alert_date = fields.Date(compute='_compute_future_alert_date') - next_countdown_date = fields.Date(compute='_compute_next_countdown_date') - - temporary_exempt_reason_id = fields.Many2one('cooperative.exempt.reason', 'Exempt Reason') + irregular_absence_counter = ( + fields.Integer() + ) # TODO unsubscribe when reach -2 + future_alert_date = fields.Date(compute="_compute_future_alert_date") + next_countdown_date = fields.Date(compute="_compute_next_countdown_date") + + temporary_exempt_reason_id = fields.Many2one( + "cooperative.exempt.reason", "Exempt Reason" + ) temporary_exempt_start_date = fields.Date() temporary_exempt_end_date = fields.Date() - @api.depends('status') + @api.depends("status") def _compute_can_shop(self): for rec in self: rec.can_shop = rec.status in self._can_shop_status() - @api.depends('today', 'sr', 'sc', 'holiday_end_time', - 'holiday_start_time', 'time_extension', - 'alert_start_time', 'extension_start_time', - 'unsubscribed', 'irregular_absence_date', - 'irregular_absence_counter', 'temporary_exempt_start_date', - 'temporary_exempt_end_date', 'resigning', 'cooperator_id.subscribed_shift_ids') + @api.depends( + "today", + "sr", + "sc", + "holiday_end_time", + "holiday_start_time", + "time_extension", + "alert_start_time", + "extension_start_time", + "unsubscribed", + "irregular_absence_date", + "irregular_absence_counter", + "temporary_exempt_start_date", + "temporary_exempt_end_date", + "resigning", + "cooperator_id.subscribed_shift_ids", + ) def _compute_status(self): - update = int(self.env['ir.config_parameter'].sudo().get_param('always_update', False)) + update = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("always_update", False) + ) for rec in self: if update or not rec.today: - rec.status = 'ok' + rec.status = "ok" continue if rec.resigning: - rec.status = 'resigning' + rec.status = "resigning" continue - if rec.working_mode == 'regular': + if rec.working_mode == "regular": rec.status = rec._get_regular_status() - elif rec.working_mode == 'irregular': + elif rec.working_mode == "irregular": rec.status = rec._get_irregular_status() - elif rec.working_mode == 'exempt': - rec.status = 'ok' + elif rec.working_mode == "exempt": + rec.status = "ok" _sql_constraints = [ - ('cooperator_uniq', 'unique (cooperator_id)', _('You can only set one cooperator status per cooperator')), + ( + "cooperator_uniq", + "unique (cooperator_id)", + _("You can only set one cooperator status per cooperator"), + ) ] @api.constrains("working_mode", "irregular_start_date") def _constrains_irregular_start_date(self): if self.working_mode == "irregular" and not self.irregular_start_date: - raise UserError(_("Irregular workers must have an irregular start date.")) + raise UserError( + _("Irregular workers must have an irregular start date.") + ) @api.multi def write(self, vals): """ Overwrite write to historize the change """ - for field in ['sr', 'sc', 'time_extension', 'extension_start_time', 'alert_start_time', 'unsubscribed']: + for field in [ + "sr", + "sc", + "time_extension", + "extension_start_time", + "alert_start_time", + "unsubscribed", + ]: if not field in vals: continue for rec in self: data = { - 'status_id': rec.id, - 'cooperator_id': rec.cooperator_id.id, - 'type': 'counter', - 'user_id': self.env.context.get('real_uid', self.env.uid), + "status_id": rec.id, + "cooperator_id": rec.cooperator_id.id, + "type": "counter", + "user_id": self.env.context.get("real_uid", self.env.uid), } if vals.get(field, rec[field]) != rec[field]: - data['change'] = '%s: %s -> %s' % (field.upper(), rec[field], vals.get(field)) - self.env['cooperative.status.history'].sudo().create(data) + data["change"] = "{}: {} -> {}".format( + field.upper(), + rec[field], + vals.get(field), + ) + self.env["cooperative.status.history"].sudo().create(data) return super(CooperativeStatus, self).write(vals) @api.multi @@ -152,28 +213,42 @@ class CooperativeStatus(models.Model): Overwrite write to historize the change of status and make action on status change """ - if 'status' in vals: - self._cr.execute('select id, status, sr, sc from "%s" where id in %%s' % self._table, (self._ids,)) + if "status" in vals: + self._cr.execute( + 'select id, status, sr, sc from "%s" where id in %%s' + % self._table, + (self._ids,), + ) result = self._cr.dictfetchall() - old_status_per_id = {r['id'] : r for r in result} + old_status_per_id = {r["id"]: r for r in result} for rec in self: - if old_status_per_id[rec.id]['status'] != vals['status']: + if old_status_per_id[rec.id]["status"] != vals["status"]: data = { - 'status_id': rec.id, - 'cooperator_id': rec.cooperator_id.id, - 'type': 'status', - 'change': "STATUS: %s -> %s" % (old_status_per_id[rec.id]['status'], vals['status']), - 'user_id': self.env.context.get('real_uid', self.env.uid), + "status_id": rec.id, + "cooperator_id": rec.cooperator_id.id, + "type": "status", + "change": "STATUS: %s -> %s" + % ( + old_status_per_id[rec.id]["status"], + vals["status"], + ), + "user_id": self.env.context.get( + "real_uid", self.env.uid + ), } - self.env['cooperative.status.history'].sudo().create(data) - rec._state_change(vals['status']) + self.env["cooperative.status.history"].sudo().create(data) + rec._state_change(vals["status"]) return super(CooperativeStatus, self)._write(vals) def get_status_value(self): """ Workararound to get translated selection value instead of key in mail template. """ - state_list = self.env["cooperative.status"]._fields['status']._description_selection(self.env) + state_list = ( + self.env["cooperative.status"] + ._fields["status"] + ._description_selection(self.env) + ) return dict(state_list)[self.status] @api.model @@ -181,7 +256,7 @@ class CooperativeStatus(models.Model): """ Method call by the cron to update store value base on the date """ - self.search([]).write({'today': fields.Date.today()}) + self.search([]).write({"today": fields.Date.today()}) @api.model def _cron_compute_counter_irregular(self, today=False): @@ -190,15 +265,21 @@ class CooperativeStatus(models.Model): once per day """ today = today or fields.Date.today() - journal = self.env['beesdoo.shift.journal'].search([('date', '=', today)]) + journal = self.env["beesdoo.shift.journal"].search( + [("date", "=", today)] + ) if not journal: - journal = self.env['beesdoo.shift.journal'].create({'date': today}) + journal = self.env["beesdoo.shift.journal"].create({"date": today}) domain = self._get_irregular_worker_domain(today=today) irregular = self.search(domain) for status in irregular: delta = (today - status.irregular_start_date).days - if delta and delta % self._period == 0 and status not in journal.line_ids: + if ( + delta + and delta % self._period == 0 + and status not in journal.line_ids + ): status._change_irregular_counter() journal.line_ids |= status @@ -217,7 +298,7 @@ class CooperativeStatus(models.Model): ############################## # Computed field section # ############################## - @api.depends('today') + @api.depends("today") def _compute_future_alert_date(self): """ Compute date until the worker is up to date @@ -226,7 +307,7 @@ class CooperativeStatus(models.Model): for rec in self: rec.future_alert_date = False - @api.depends('today') + @api.depends("today") def _compute_next_countdown_date(self): """ Compute the following countdown date. This date is the date when @@ -242,7 +323,7 @@ class CooperativeStatus(models.Model): return the list of status that give access to active cooperator privilege """ - return ['ok', 'alert', 'extension', 'exempted'] + return ["ok", "alert", "extension", "exempted"] ##################################### # Status Change implementation # @@ -253,14 +334,14 @@ class CooperativeStatus(models.Model): Return the value of the status for the regular worker """ - return 'ok' + return "ok" def _get_irregular_status(self): """ Return the value of the status for the irregular worker """ - return 'ok' + return "ok" def _state_change(self, new_state): """ @@ -275,7 +356,6 @@ class CooperativeStatus(models.Model): """ pass - ############################################### ###### Irregular Cron implementation ########## ############################################### @@ -286,7 +366,7 @@ class CooperativeStatus(models.Model): of valid irregular worker that should get their counter changed by the cron """ - return [(0, '=', 1)] + return [(0, "=", 1)] def _change_irregular_counter(self): """ @@ -297,22 +377,31 @@ class CooperativeStatus(models.Model): """ pass + class ShiftCronJournal(models.Model): - _name = 'beesdoo.shift.journal' - _description = 'beesdoo.shift.journal' - _order = 'date desc' - _rec_name = 'date' + _name = "beesdoo.shift.journal" + _description = "beesdoo.shift.journal" + _order = "date desc" + _rec_name = "date" date = fields.Date() - line_ids = fields.Many2many('cooperative.status') + line_ids = fields.Many2many("cooperative.status") _sql_constraints = [ - ('one_entry_per_day', 'unique (date)', _('You can only create one journal per day')), + ( + "one_entry_per_day", + "unique (date)", + _("You can only create one journal per day"), + ) ] @api.multi def run(self): self.ensure_one() - if not self.user_has_groups('beesdoo_shift.group_cooperative_admin'): - raise ValidationError(_("You don't have the access to perform this action")) - self.sudo().env['cooperative.status']._cron_compute_counter_irregular(today=self.date) + if not self.user_has_groups("beesdoo_shift.group_cooperative_admin"): + raise ValidationError( + _("You don't have the access to perform this action") + ) + self.sudo().env["cooperative.status"]._cron_compute_counter_irregular( + today=self.date + ) diff --git a/beesdoo_shift/models/planning.py b/beesdoo_shift/models/planning.py index 63fd3fd..d5293a3 100644 --- a/beesdoo_shift/models/planning.py +++ b/beesdoo_shift/models/planning.py @@ -1,54 +1,67 @@ - -from odoo import models, fields, api, _ -from odoo.exceptions import UserError - -from pytz import timezone, UTC import math from datetime import datetime, time, timedelta +from pytz import UTC, timezone + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + def float_to_time(f): decimal, integer = math.modf(f) - return "%s:%s" % (str(int(integer)).zfill(2), str(int(round(decimal * 60))).zfill(2)) + return "{}:{}".format( + str(int(integer)).zfill(2), + str(int(round(decimal * 60))).zfill(2), + ) + def floatime_to_hour_minute(f): decimal, integer = math.modf(f) return int(integer), int(round(decimal * 60)) + def get_first_day_of_week(): today = datetime.now() return (datetime.now() - timedelta(days=today.weekday())).date() + class TaskType(models.Model): - _name = 'beesdoo.shift.type' - _description = 'beesdoo.shift.type' + _name = "beesdoo.shift.type" + _description = "beesdoo.shift.type" name = fields.Char() description = fields.Text() active = fields.Boolean(default=True) + class DayNumber(models.Model): - _name = 'beesdoo.shift.daynumber' - _description = 'beesdoo.shift.daynumber' + _name = "beesdoo.shift.daynumber" + _description = "beesdoo.shift.daynumber" - _order = 'number asc' + _order = "number asc" name = fields.Char() - number = fields.Integer("Day Number", help="From 1 to N, When you will instanciate your planning, Day 1 will be the start date of the instance, Day 2 the second, etc...") + number = fields.Integer( + "Day Number", + help="From 1 to N, When you will instanciate your planning, Day 1 will be the start date of the instance, Day 2 the second, etc...", + ) active = fields.Boolean(default=True) + class Planning(models.Model): - _name = 'beesdoo.shift.planning' - _description = 'beesdoo.shift.planning' - _order = 'sequence asc' + _name = "beesdoo.shift.planning" + _description = "beesdoo.shift.planning" + _order = "sequence asc" sequence = fields.Integer() name = fields.Char() - task_template_ids = fields.One2many('beesdoo.shift.template', 'planning_id') + task_template_ids = fields.One2many( + "beesdoo.shift.template", "planning_id" + ) @api.model def _get_next_planning(self, sequence): - next_planning = self.search([('sequence', '>', sequence)]) + next_planning = self.search([("sequence", ">", sequence)]) if not next_planning: return self.search([])[0] return next_planning[0] @@ -56,15 +69,15 @@ class Planning(models.Model): @api.multi def _get_next_planning_date(self, date): self.ensure_one() - nb_of_day = max(self.task_template_ids.mapped('day_nb_id.number')) + nb_of_day = max(self.task_template_ids.mapped("day_nb_id.number")) return date + timedelta(days=nb_of_day) @api.model def _generate_next_planning(self): - config = self.env['ir.config_parameter'].sudo() - last_seq = int(config.get_param('last_planning_seq', 0)) + config = self.env["ir.config_parameter"].sudo() + last_seq = int(config.get_param("last_planning_seq", 0)) date = fields.Date.from_string( - config.get_param('next_planning_date', 0) + config.get_param("next_planning_date", 0) ) planning = self._get_next_planning(last_seq) @@ -72,49 +85,70 @@ class Planning(models.Model): planning.task_template_ids._generate_task_day() next_date = planning._get_next_planning_date(date) - config.set_param('last_planning_seq', planning.sequence) - config.set_param('next_planning_date', next_date) + config.set_param("last_planning_seq", planning.sequence) + config.set_param("next_planning_date", next_date) + class TaskTemplate(models.Model): - _name = 'beesdoo.shift.template' - _description = 'beesdoo.shift.template' - _order = 'start_time' + _name = "beesdoo.shift.template" + _description = "beesdoo.shift.template" + _order = "start_time" name = fields.Char(required=True) - planning_id = fields.Many2one('beesdoo.shift.planning', required=True) - day_nb_id = fields.Many2one('beesdoo.shift.daynumber', string='Day', required=True) - task_type_id = fields.Many2one('beesdoo.shift.type', string="Type") - # attendance_sheet_id = fields.Many2one('beesdoo.shift.sheet', string="Attendance Sheet") FIXME removed because beesdoo.shift.sheet is from another module. + planning_id = fields.Many2one("beesdoo.shift.planning", required=True) + day_nb_id = fields.Many2one( + "beesdoo.shift.daynumber", string="Day", required=True + ) + task_type_id = fields.Many2one("beesdoo.shift.type", string="Type") + # attendance_sheet_id = fields.Many2one('beesdoo.shift.sheet', string="Attendance Sheet") FIXME removed because beesdoo.shift.sheet is from another module. start_time = fields.Float(required=True) end_time = fields.Float(required=True) - super_coop_id = fields.Many2one('res.users', string="Super Cooperative", domain=[('partner_id.super', '=', True)]) + super_coop_id = fields.Many2one( + "res.users", + string="Super Cooperative", + domain=[("partner_id.super", "=", True)], + ) duration = fields.Float(help="Duration in Hour") - worker_nb = fields.Integer(string="Number of worker", help="Max number of worker for this task", default=1) - worker_ids = fields.Many2many('res.partner', string="Recurrent worker assigned", domain=[('is_worker', '=', True)]) - remaining_worker = fields.Integer(compute="_get_remaining", store=True, string="Remaining Place") + worker_nb = fields.Integer( + string="Number of worker", + help="Max number of worker for this task", + default=1, + ) + worker_ids = fields.Many2many( + "res.partner", + string="Recurrent worker assigned", + domain=[("is_worker", "=", True)], + ) + remaining_worker = fields.Integer( + compute="_get_remaining", store=True, string="Remaining Place" + ) active = fields.Boolean(default=True) - #For Kanban View Only - color = fields.Integer('Color Index') + # For Kanban View Only + color = fields.Integer("Color Index") worker_name = fields.Char(compute="_get_worker_name") - #For calendar View - start_date = fields.Datetime(compute="_get_fake_date", search="_dummy_search") - end_date = fields.Datetime(compute="_get_fake_date", search="_dummy_search") + # For calendar View + start_date = fields.Datetime( + compute="_get_fake_date", search="_dummy_search" + ) + end_date = fields.Datetime( + compute="_get_fake_date", search="_dummy_search" + ) def _get_utc_date(self, day, hour, minute): """Combine day number, hours and minutes to save corresponding UTC datetime in database. """ - context_tz = timezone(self._context.get('tz') or self.env.user.tz) + context_tz = timezone(self._context.get("tz") or self.env.user.tz) day_local_time = datetime.combine(day, time(hour=hour, minute=minute)) day_local_time = context_tz.localize(day_local_time) day_utc_time = day_local_time.astimezone(UTC) # Return naïve datetime so as to be saved in database - return day_utc_time.replace(tzinfo=None) + return day_utc_time.replace(tzinfo=None) - @api.depends('start_time', 'end_time') + @api.depends("start_time", "end_time") def _get_fake_date(self): - today = self._context.get('visualize_date', get_first_day_of_week()) + today = self._context.get("visualize_date", get_first_day_of_week()) for rec in self: # Find the day of this task template 'rec'. day = today + timedelta(days=rec.day_nb_id.number - 1) @@ -128,84 +162,109 @@ class TaskTemplate(models.Model): def _dummy_search(self, operator, value): return [] - @api.depends('worker_ids', 'worker_nb') + @api.depends("worker_ids", "worker_nb") def _get_remaining(self): for rec in self: - rec.remaining_worker = rec.worker_nb - len(rec.worker_ids) + rec.remaining_worker = rec.worker_nb - len(rec.worker_ids) @api.depends("worker_ids") def _get_worker_name(self): for rec in self: - rec.worker_name = ','.join(rec.worker_ids.mapped('display_name')) + rec.worker_name = ",".join(rec.worker_ids.mapped("display_name")) - @api.constrains('worker_nb', 'worker_ids') + @api.constrains("worker_nb", "worker_ids") def _nb_worker_max(self): for rec in self: if len(rec.worker_ids) > rec.worker_nb: - raise UserError(_('You cannot assign more workers than the maximal number defined on template.')) - + raise UserError( + _( + "You cannot assign more workers than the maximal number defined on template." + ) + ) - @api.onchange('start_time', 'end_time') + @api.onchange("start_time", "end_time") def _get_duration(self): if self.start_time and self.end_time: self.duration = self.end_time - self.start_time - @api.onchange('duration') + @api.onchange("duration") def _set_duration(self): if self.start_time: - self.end_time = self.start_time +self.duration + self.end_time = self.start_time + self.duration def _generate_task_day(self): - tasks = self.env['beesdoo.shift.shift'] + tasks = self.env["beesdoo.shift.shift"] for rec in self: for i in range(0, rec.worker_nb): - worker_id = rec.worker_ids[i] if len(rec.worker_ids) > i else False - #remove worker in holiday and temporary exempted + worker_id = ( + rec.worker_ids[i] if len(rec.worker_ids) > i else False + ) + # remove worker in holiday and temporary exempted if worker_id and worker_id.cooperative_status_ids: status = worker_id.cooperative_status_ids[0] - if status.holiday_start_time and status.holiday_end_time and \ - status.holiday_start_time <= rec.start_date.date() and status.holiday_end_time >= rec.end_date.date(): + if ( + status.holiday_start_time + and status.holiday_end_time + and status.holiday_start_time <= rec.start_date.date() + and status.holiday_end_time >= rec.end_date.date() + ): worker_id = False - if status.temporary_exempt_start_date and status.temporary_exempt_end_date and \ - status.temporary_exempt_start_date <= rec.start_date.date() and status.temporary_exempt_end_date >= rec.end_date.date(): + if ( + status.temporary_exempt_start_date + and status.temporary_exempt_end_date + and status.temporary_exempt_start_date + <= rec.start_date.date() + and status.temporary_exempt_end_date + >= rec.end_date.date() + ): worker_id = False - tasks |= tasks.create({ - 'name' : "[%s] %s %s (%s - %s) [%s]" % ( - rec.start_date.date(), - rec.planning_id.name, - rec.day_nb_id.name, - float_to_time(rec.start_time), - float_to_time(rec.end_time), - i, - ), - 'task_template_id' : rec.id, - 'task_type_id' : rec.task_type_id.id, - 'super_coop_id': rec.super_coop_id.id, - 'worker_id' : worker_id and worker_id.id or False, - 'is_regular': True if worker_id else False, - 'start_time' : rec.start_date, - 'end_time' : rec.end_date, - 'state': 'open', - }) + tasks |= tasks.create( + { + "name": "[%s] %s %s (%s - %s) [%s]" + % ( + rec.start_date.date(), + rec.planning_id.name, + rec.day_nb_id.name, + float_to_time(rec.start_time), + float_to_time(rec.end_time), + i, + ), + "task_template_id": rec.id, + "task_type_id": rec.task_type_id.id, + "super_coop_id": rec.super_coop_id.id, + "worker_id": worker_id and worker_id.id or False, + "is_regular": True if worker_id else False, + "start_time": rec.start_date, + "end_time": rec.end_date, + "state": "open", + } + ) return tasks - @api.onchange('worker_ids') + @api.onchange("worker_ids") def check_for_multiple_shifts(self): original_ids = {worker.id for worker in self._origin.worker_ids} warnings = [] for worker in self.worker_ids: if worker.id not in original_ids: - shifts = [shift.name for shift in worker.subscribed_shift_ids if shift.id != self.id] + shifts = [ + shift.name + for shift in worker.subscribed_shift_ids + if shift.id != self.id + ] if shifts: warnings.append( - worker.name + _(' is already assigned to ') + ", ".join(shifts)) + worker.name + + _(" is already assigned to ") + + ", ".join(shifts) + ) if warnings: return { - 'warning': { - 'title': _("Warning"), - 'message': "\n".join(warnings) + "warning": { + "title": _("Warning"), + "message": "\n".join(warnings), } } diff --git a/beesdoo_shift/models/res_partner.py b/beesdoo_shift/models/res_partner.py index 7cefcbe..7323d7a 100644 --- a/beesdoo_shift/models/res_partner.py +++ b/beesdoo_shift/models/res_partner.py @@ -1,8 +1,8 @@ -from odoo import models, fields, api, _ -from odoo.exceptions import ValidationError, UserError - -from datetime import timedelta, datetime import logging +from datetime import datetime, timedelta + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError class ResPartner(models.Model): @@ -10,20 +10,59 @@ class ResPartner(models.Model): One2many relationship with CooperativeStatus should be replaced by inheritance. """ - _inherit = 'res.partner' + + _inherit = "res.partner" worker_store = fields.Boolean(default=False) - is_worker = fields.Boolean(related="worker_store", string="Worker", readonly=False) - can_shop = fields.Boolean(string="Is worker allowed to shop?", compute="_compute_can_shop", store=True) - cooperative_status_ids = fields.One2many('cooperative.status', 'cooperator_id', readonly=True) - super = fields.Boolean(related='cooperative_status_ids.super', string="Super Cooperative", readonly=True, store=True) - info_session = fields.Boolean(related='cooperative_status_ids.info_session', string='Information Session ?', readonly=True, store=True) - info_session_date = fields.Date(related='cooperative_status_ids.info_session_date', string='Information Session Date', readonly=True, store=True) - working_mode = fields.Selection(related='cooperative_status_ids.working_mode', readonly=True, store=True) - exempt_reason_id = fields.Many2one(related='cooperative_status_ids.exempt_reason_id', readonly=True, store=True) - state = fields.Selection(related='cooperative_status_ids.status', readonly=True, store=True) - extension_start_time = fields.Date(related='cooperative_status_ids.extension_start_time', string="Extension Start Day", readonly=True, store=True) - subscribed_shift_ids = fields.Many2many('beesdoo.shift.template') + is_worker = fields.Boolean( + related="worker_store", string="Worker", readonly=False + ) + can_shop = fields.Boolean( + string="Is worker allowed to shop?", + compute="_compute_can_shop", + store=True, + ) + cooperative_status_ids = fields.One2many( + "cooperative.status", "cooperator_id", readonly=True + ) + super = fields.Boolean( + related="cooperative_status_ids.super", + string="Super Cooperative", + readonly=True, + store=True, + ) + info_session = fields.Boolean( + related="cooperative_status_ids.info_session", + string="Information Session ?", + readonly=True, + store=True, + ) + info_session_date = fields.Date( + related="cooperative_status_ids.info_session_date", + string="Information Session Date", + readonly=True, + store=True, + ) + working_mode = fields.Selection( + related="cooperative_status_ids.working_mode", + readonly=True, + store=True, + ) + exempt_reason_id = fields.Many2one( + related="cooperative_status_ids.exempt_reason_id", + readonly=True, + store=True, + ) + state = fields.Selection( + related="cooperative_status_ids.status", readonly=True, store=True + ) + extension_start_time = fields.Date( + related="cooperative_status_ids.extension_start_time", + string="Extension Start Day", + readonly=True, + store=True, + ) + subscribed_shift_ids = fields.Many2many("beesdoo.shift.template") @api.depends("cooperative_status_ids") def _compute_can_shop(self): @@ -41,58 +80,58 @@ class ResPartner(models.Model): @api.multi def coop_subscribe(self): return { - 'name': _('Subscribe Cooperator'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'beesdoo.shift.subscribe', - 'target': 'new', + "name": _("Subscribe Cooperator"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "form", + "res_model": "beesdoo.shift.subscribe", + "target": "new", } @api.multi def coop_unsubscribe(self): res = self.coop_subscribe() - res['context'] = {'default_unsubscribed': True} + res["context"] = {"default_unsubscribed": True} return res @api.multi def manual_extension(self): return { - 'name': _('Manual Extension'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'beesdoo.shift.extension', - 'target': 'new', + "name": _("Manual Extension"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "form", + "res_model": "beesdoo.shift.extension", + "target": "new", } @api.multi def auto_extension(self): res = self.manual_extension() - res['context'] = {'default_auto': True} - res['name'] = _('Trigger Grace Delay') + res["context"] = {"default_auto": True} + res["name"] = _("Trigger Grace Delay") return res @api.multi def register_holiday(self): return { - 'name': _('Register Holiday'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'beesdoo.shift.holiday', - 'target': 'new', + "name": _("Register Holiday"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "form", + "res_model": "beesdoo.shift.holiday", + "target": "new", } @api.multi def temporary_exempt(self): return { - 'name': _('Temporary Exemption'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'beesdoo.shift.temporary_exemption', - 'target': 'new', + "name": _("Temporary Exemption"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "form", + "res_model": "beesdoo.shift.temporary_exemption", + "target": "new", } - #TODO access right + vue on res.partner + # TODO access right + vue on res.partner diff --git a/beesdoo_shift/models/task.py b/beesdoo_shift/models/task.py index 3f8a871..12b69d1 100644 --- a/beesdoo_shift/models/task.py +++ b/beesdoo_shift/models/task.py @@ -5,11 +5,10 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError - class Task(models.Model): - _name = 'beesdoo.shift.shift' + _name = "beesdoo.shift.shift" - _inherit = ['mail.thread'] + _inherit = ["mail.thread"] _order = "start_time asc" @@ -20,11 +19,11 @@ class Task(models.Model): ################################## def _get_selection_status(self): return [ - ("open","Confirmed"), - ("done","Attended"), - ("absent","Absent"), - ("excused","Excused"), - ("cancel","Cancelled") + ("open", "Confirmed"), + ("done", "Attended"), + ("absent", "Absent"), + ("excused", "Excused"), + ("cancel", "Cancelled"), ] def _get_color_mapping(self, state): @@ -40,40 +39,57 @@ class Task(models.Model): def _get_final_state(self): return ["done", "absent", "excused"] - name = fields.Char(track_visibility='always') - task_template_id = fields.Many2one('beesdoo.shift.template') - planning_id = fields.Many2one(related='task_template_id.planning_id', store=True) - task_type_id = fields.Many2one('beesdoo.shift.type', string="Task Type") - worker_id = fields.Many2one('res.partner', track_visibility='onchange', - domain=[ - ('is_worker', '=', True), - ('working_mode', 'in', ('regular', 'irregular')), - ('state', 'not in', ('unsubscribed', 'resigning')), - ]) - start_time = fields.Datetime(track_visibility='always', index=True, required=True) - end_time = fields.Datetime(track_visibility='always', required=True) - state = fields.Selection(selection=_get_selection_status, + name = fields.Char(track_visibility="always") + task_template_id = fields.Many2one("beesdoo.shift.template") + planning_id = fields.Many2one( + related="task_template_id.planning_id", store=True + ) + task_type_id = fields.Many2one("beesdoo.shift.type", string="Task Type") + worker_id = fields.Many2one( + "res.partner", + track_visibility="onchange", + domain=[ + ("is_worker", "=", True), + ("working_mode", "in", ("regular", "irregular")), + ("state", "not in", ("unsubscribed", "resigning")), + ], + ) + start_time = fields.Datetime( + track_visibility="always", index=True, required=True + ) + end_time = fields.Datetime(track_visibility="always", required=True) + state = fields.Selection( + selection=_get_selection_status, default="open", required=True, - track_visibility='onchange', - group_expand='_expand_states' + track_visibility="onchange", + group_expand="_expand_states", ) color = fields.Integer(compute="_compute_color") - super_coop_id = fields.Many2one('res.users', string="Super Cooperative", domain=[('partner_id.super', '=', True)], track_visibility='onchange') + super_coop_id = fields.Many2one( + "res.users", + string="Super Cooperative", + domain=[("partner_id.super", "=", True)], + track_visibility="onchange", + ) is_regular = fields.Boolean(default=False, string="Regular shift") - is_compensation = fields.Boolean(default=False, string="Compensation shift") - replaced_id = fields.Many2one('res.partner', track_visibility='onchange', - domain=[ - ('eater', '=', 'worker_eater'), - ('working_mode', '=', 'regular'), - ('state', 'not in', ('unsubscribed', 'resigning')), - ]) + is_compensation = fields.Boolean( + default=False, string="Compensation shift" + ) + replaced_id = fields.Many2one( + "res.partner", + track_visibility="onchange", + domain=[ + ("eater", "=", "worker_eater"), + ("working_mode", "=", "regular"), + ("state", "not in", ("unsubscribed", "resigning")), + ], + ) revert_info = fields.Text(copy=False) - working_mode = fields.Selection(related='worker_id.working_mode') + working_mode = fields.Selection(related="worker_id.working_mode") def _expand_states(self, states, domain, order): - return [key for key, val in self._fields['state'].selection] - + return [key for key, val in self._fields["state"].selection] @api.depends("state") def _compute_color(self): @@ -85,8 +101,9 @@ class Task(models.Model): Raise a validation error if the fields is_regular and is_compensation are not properly set. """ - if (task.is_regular == task.is_compensation - or not (task.is_regular or task.is_compensation)): + if task.is_regular == task.is_compensation or not ( + task.is_regular or task.is_compensation + ): raise ValidationError( "You must choose between Regular Shift or " "Compensation Shift." @@ -96,18 +113,20 @@ class Task(models.Model): def _lock_future_task(self): if datetime.now() < self.start_time: if self.state in self._get_final_state(): - raise UserError(_( - "Shift state of a future shift " - "can't be set to 'present' or 'absent'." - )) - - @api.constrains('is_regular', 'is_compensation') + raise UserError( + _( + "Shift state of a future shift " + "can't be set to 'present' or 'absent'." + ) + ) + + @api.constrains("is_regular", "is_compensation") def _check_compensation(self): for task in self: - if task.working_mode == 'regular': + if task.working_mode == "regular": self._compensation_validation(task) - @api.constrains('worker_id') + @api.constrains("worker_id") def _check_worker_id(self): """ When worker_id changes we need to check whether is_regular @@ -117,29 +136,30 @@ class Task(models.Model): False. """ for task in self: - if task.working_mode == 'regular': + if task.working_mode == "regular": self._compensation_validation(task) else: - task.write({ - 'is_regular': False, - 'is_compensation': False, - }) + task.write({"is_regular": False, "is_compensation": False}) if task.worker_id: if task.worker_id == task.replaced_id: raise UserError("A worker cannot replace himself.") def message_auto_subscribe(self, updated_fields, values=None): self._add_follower(values) - return super(Task, self).message_auto_subscribe(updated_fields, values=values) + return super(Task, self).message_auto_subscribe( + updated_fields, values=values + ) def _add_follower(self, vals): - if vals.get('worker_id'): - worker = self.env['res.partner'].browse(vals['worker_id']) + if vals.get("worker_id"): + worker = self.env["res.partner"].browse(vals["worker_id"]) self.message_subscribe(partner_ids=worker.ids) - #TODO button to replaced someone + # TODO button to replaced someone @api.model - def unsubscribe_from_today(self, worker_ids, today=None, end_date=None, now=None): + def unsubscribe_from_today( + self, worker_ids, today=None, end_date=None, now=None + ): """ Unsubscribe workers from *worker_ids* from all shift that start *today* and later. If *end_date* is given, unsubscribe workers from shift between *today* and *end_date*. @@ -152,31 +172,43 @@ class Task(models.Model): """ if now: if not isinstance(now, datetime): - raise UserError (_("'Now' must be a datetime.")) - date_domain = [('start_time', '>', now)] + raise UserError(_("'Now' must be a datetime.")) + date_domain = [("start_time", ">", now)] else: today = today or fields.Date.today() today = datetime.combine(today, time()) - date_domain = [('start_time', '>', today)] + date_domain = [("start_time", ">", today)] if end_date: - end_date = datetime.combine(end_date,time(hour=23, minute=59, second=59)) - date_domain.append(('end_time', '<=', end_date)) + end_date = datetime.combine( + end_date, time(hour=23, minute=59, second=59) + ) + date_domain.append(("end_time", "<=", end_date)) - to_unsubscribe = self.search([('worker_id', 'in', worker_ids)] + date_domain) - to_unsubscribe.write({'worker_id': False}) + to_unsubscribe = self.search( + [("worker_id", "in", worker_ids)] + date_domain + ) + to_unsubscribe.write({"worker_id": False}) # Remove worker, replaced_id and regular - to_unsubscribe_replace = self.search([('replaced_id', 'in', worker_ids)] + date_domain) - to_unsubscribe_replace.write({'worker_id': False, 'replaced_id': False}) + to_unsubscribe_replace = self.search( + [("replaced_id", "in", worker_ids)] + date_domain + ) + to_unsubscribe_replace.write( + {"worker_id": False, "replaced_id": False} + ) # If worker is Super cooperator, remove it from planning - super_coop_ids = self.env['res.users'].search( - [('partner_id', 'in', worker_ids), ('super', '=', True)]).ids + super_coop_ids = ( + self.env["res.users"] + .search([("partner_id", "in", worker_ids), ("super", "=", True)]) + .ids + ) if super_coop_ids: to_unsubscribe_super_coop = self.search( - [('super_coop_id', 'in', super_coop_ids)] + date_domain) - to_unsubscribe_super_coop.write({'super_coop_id': False}) + [("super_coop_id", "in", super_coop_ids)] + date_domain + ) + to_unsubscribe_super_coop.write({"super_coop_id": False}) @api.multi def write(self, vals): @@ -187,56 +219,82 @@ class Task(models.Model): Change the worker info Compute state change for the new worker """ - if 'worker_id' in vals: + if "worker_id" in vals: for rec in self: - if rec.worker_id.id != vals['worker_id']: + if rec.worker_id.id != vals["worker_id"]: rec._revert() # To satisfy the constrains on worker_id, it must be # accompanied by the change in is_regular and # is_compensation field. - super(Task, rec).write({ - 'worker_id': vals['worker_id'], - 'is_regular': vals.get('is_regular', rec.is_regular), - 'is_compensation': vals.get('is_compensation', - rec.is_compensation), - }) + super(Task, rec).write( + { + "worker_id": vals["worker_id"], + "is_regular": vals.get( + "is_regular", rec.is_regular + ), + "is_compensation": vals.get( + "is_compensation", rec.is_compensation + ), + } + ) rec._update_state(rec.state) - if 'state' in vals: + if "state" in vals: for rec in self: - if vals['state'] != rec.state: - rec._update_state(vals['state']) + if vals["state"] != rec.state: + rec._update_state(vals["state"]) return super(Task, self).write(vals) def _set_revert_info(self, data, status): data_new = { - 'status_id': status.id, - 'data' : {k: data.get(k, 0) * -1 for k in ['sr', 'sc', 'irregular_absence_counter']} + "status_id": status.id, + "data": { + k: data.get(k, 0) * -1 + for k in ["sr", "sc", "irregular_absence_counter"] + }, } - if data.get('irregular_absence_date'): - data_new['data']['irregular_absence_date'] = False + if data.get("irregular_absence_date"): + data_new["data"]["irregular_absence_date"] = False - self.write({'revert_info': json.dumps(data_new)}) + self.write({"revert_info": json.dumps(data_new)}) def _revert(self): if not self.revert_info: return data = json.loads(self.revert_info) - self.env['cooperative.status'].browse(data['status_id']).sudo()._change_counter(data['data']) + self.env["cooperative.status"].browse( + data["status_id"] + ).sudo()._change_counter(data["data"]) self.revert_info = False def _update_state(self, new_state): self.ensure_one() self._revert() - if not (self.worker_id or self.replaced_id) and new_state in self._get_final_state(): - raise UserError(_("You cannot change to the status %s if no worker is defined for the shift") % new_state) + if ( + not (self.worker_id or self.replaced_id) + and new_state in self._get_final_state() + ): + raise UserError( + _( + "You cannot change to the status %s if no worker is defined for the shift" + ) + % new_state + ) - always_update = int(self.env['ir.config_parameter'].sudo().get_param('always_update', False)) + always_update = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("always_update", False) + ) if always_update or not (self.worker_id or self.replaced_id): return - if not (self.worker_id.working_mode in ['regular', 'irregular']): - raise UserError(_("Working mode is not properly defined. Please check if the worker is subscribed")) + if not (self.worker_id.working_mode in ["regular", "irregular"]): + raise UserError( + _( + "Working mode is not properly defined. Please check if the worker is subscribed" + ) + ) data, status = self._get_counter_date_state_change(new_state) if status: diff --git a/beesdoo_shift/readme/CONTRIBUTORS.rst b/beesdoo_shift/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_shift/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_shift/wizard/assign_super_coop.py b/beesdoo_shift/wizard/assign_super_coop.py index 8eef0db..638e0b7 100644 --- a/beesdoo_shift/wizard/assign_super_coop.py +++ b/beesdoo_shift/wizard/assign_super_coop.py @@ -1,14 +1,23 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models class AssignSuperCoop(models.TransientModel): - _name = 'beesddoo.shift.assign_super_coop' - _description = 'beesddoo.shift.assign_super_coop' + _name = "beesddoo.shift.assign_super_coop" + _description = "beesddoo.shift.assign_super_coop" - super_coop_id = fields.Many2one('res.users', 'New Super Cooperative', required=True, domain=[('super', '=', True)]) - shift_ids = fields.Many2many('beesdoo.shift.shift', readonly=True, default=lambda self: self._context.get('active_ids')) + super_coop_id = fields.Many2one( + "res.users", + "New Super Cooperative", + required=True, + domain=[("super", "=", True)], + ) + shift_ids = fields.Many2many( + "beesdoo.shift.shift", + readonly=True, + default=lambda self: self._context.get("active_ids"), + ) @api.multi def write_super_coop(self): self.ensure_one() - self.shift_ids.write({'super_coop_id' : self.super_coop_id.id}) + self.shift_ids.write({"super_coop_id": self.super_coop_id.id}) diff --git a/beesdoo_shift/wizard/batch_template.py b/beesdoo_shift/wizard/batch_template.py index 5ffbdcb..f0ffb32 100644 --- a/beesdoo_shift/wizard/batch_template.py +++ b/beesdoo_shift/wizard/batch_template.py @@ -1,19 +1,30 @@ -''' +""" Created on 2 janv. 2017 @author: Thibault Francois -''' +""" + +from odoo import _, api, fields, models -from odoo import models, fields, api, _ class GenerateShiftTemplate(models.TransientModel): - _name = 'beesddoo.shift.generate_shift_template' - _description = 'beesddoo.shift.generate_shift_template' + _name = "beesddoo.shift.generate_shift_template" + _description = "beesddoo.shift.generate_shift_template" - day_ids = fields.Many2many('beesdoo.shift.daynumber', relation='template_gen_day_number_rel', column1='wizard_id', column2='day_id') - planning_id = fields.Many2one('beesdoo.shift.planning', required=True) - type_id = fields.Many2one('beesdoo.shift.type', default=lambda self: self._context.get('active_id')) - line_ids = fields.One2many('beesddoo.shift.generate_shift_template.line', 'wizard_id') + day_ids = fields.Many2many( + "beesdoo.shift.daynumber", + relation="template_gen_day_number_rel", + column1="wizard_id", + column2="day_id", + ) + planning_id = fields.Many2one("beesdoo.shift.planning", required=True) + type_id = fields.Many2one( + "beesdoo.shift.type", + default=lambda self: self._context.get("active_id"), + ) + line_ids = fields.One2many( + "beesddoo.shift.generate_shift_template.line", "wizard_id" + ) @api.multi def generate(self): @@ -22,33 +33,36 @@ class GenerateShiftTemplate(models.TransientModel): for day in self.day_ids: for line in self.line_ids: shift_template_data = { - 'name': '%s' % self.type_id.name, - 'planning_id': self.planning_id.id, - 'task_type_id': self.type_id.id, - 'day_nb_id': day.id, - 'start_time': line.start_time, - 'end_time': line.end_time, - 'duration': line.end_time - line.start_time, - 'worker_nb': line.worker_nb, + "name": "%s" % self.type_id.name, + "planning_id": self.planning_id.id, + "task_type_id": self.type_id.id, + "day_nb_id": day.id, + "start_time": line.start_time, + "end_time": line.end_time, + "duration": line.end_time - line.start_time, + "worker_nb": line.worker_nb, } - new_rec = self.env['beesdoo.shift.template'].create(shift_template_data) + new_rec = self.env["beesdoo.shift.template"].create( + shift_template_data + ) ids.append(new_rec.id) return { - 'name': _('Generated Shift Template'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'kanban,tree,form', - 'res_model': 'beesdoo.shift.template', - 'target': 'current', - 'domain': [('id', 'in', ids)], - 'context': {'group_by': 'day_nb_id'}, + "name": _("Generated Shift Template"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "kanban,tree,form", + "res_model": "beesdoo.shift.template", + "target": "current", + "domain": [("id", "in", ids)], + "context": {"group_by": "day_nb_id"}, } + class GenerateShiftTemplateLine(models.TransientModel): - _name = 'beesddoo.shift.generate_shift_template.line' - _description = 'beesddoo.shift.generate_shift_template.line' + _name = "beesddoo.shift.generate_shift_template.line" + _description = "beesddoo.shift.generate_shift_template.line" - wizard_id = fields.Many2one('beesddoo.shift.generate_shift_template') + wizard_id = fields.Many2one("beesddoo.shift.generate_shift_template") start_time = fields.Float(required=True) end_time = fields.Float(required=True) worker_nb = fields.Integer(default=1) diff --git a/beesdoo_shift/wizard/extension.py b/beesdoo_shift/wizard/extension.py index a351a83..582a937 100644 --- a/beesdoo_shift/wizard/extension.py +++ b/beesdoo_shift/wizard/extension.py @@ -1,33 +1,63 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import UserError + class Subscribe(models.TransientModel): - _name = 'beesdoo.shift.extension' - _description = 'beesdoo.shift.extension' - _inherit = 'beesdoo.shift.action_mixin' + _name = "beesdoo.shift.extension" + _description = "beesdoo.shift.extension" + _inherit = "beesdoo.shift.action_mixin" def _get_default_extension_delay(self): - return int(self.env['ir.config_parameter'].sudo().get_param('default_extension_delay', 28)) - + return int( + self.env["ir.config_parameter"] + .sudo() + .get_param("default_extension_delay", 28) + ) - extension_start_date = fields.Date(string="Start date for the extension", default=fields.Date.today, readonly=True) + extension_start_date = fields.Date( + string="Start date for the extension", + default=fields.Date.today, + readonly=True, + ) auto = fields.Boolean("Auto Extension", default=False) extension_days = fields.Integer(default=_get_default_extension_delay) @api.multi def auto_ext(self): - self = self._check(group='beesdoo_shift.group_shift_attendance') - status_id = self.env['cooperative.status'].search([('cooperator_id', '=', self.cooperator_id.id)]) - status_id.sudo().write({'extension_start_time': self.extension_start_date}) + self = self._check(group="beesdoo_shift.group_shift_attendance") + status_id = self.env["cooperative.status"].search( + [("cooperator_id", "=", self.cooperator_id.id)] + ) + status_id.sudo().write( + {"extension_start_time": self.extension_start_date} + ) @api.multi def extension(self): - self = self._check() #maybe a different group - grace_delay = int(self.env['ir.config_parameter'].sudo().get_param('default_grace_delay', 10)) - status_id = self.env['cooperative.status'].search([('cooperator_id', '=', self.cooperator_id.id)]) + self = self._check() # maybe a different group + grace_delay = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("default_grace_delay", 10) + ) + status_id = self.env["cooperative.status"].search( + [("cooperator_id", "=", self.cooperator_id.id)] + ) if not status_id.extension_start_time: - raise UserError(_('You should not make a manual extension when the grace delay has not been triggered yet')) - today_delay = (status_id.today - status_id.extension_start_time).days - grace_delay + raise UserError( + _( + "You should not make a manual extension when the grace delay has not been triggered yet" + ) + ) + today_delay = ( + status_id.today - status_id.extension_start_time + ).days - grace_delay if today_delay < 0: - raise UserError(_('You should not start a manual extension during the grace delay')) - status_id.sudo().write({'time_extension': self.extension_days + today_delay}) + raise UserError( + _( + "You should not start a manual extension during the grace delay" + ) + ) + status_id.sudo().write( + {"time_extension": self.extension_days + today_delay} + ) diff --git a/beesdoo_shift/wizard/holiday.py b/beesdoo_shift/wizard/holiday.py index ab55d0a..e91f562 100644 --- a/beesdoo_shift/wizard/holiday.py +++ b/beesdoo_shift/wizard/holiday.py @@ -1,19 +1,40 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError + class Subscribe(models.TransientModel): - _name = 'beesdoo.shift.holiday' - _description = 'beesdoo.shift.holiday' - _inherit = 'beesdoo.shift.action_mixin' + _name = "beesdoo.shift.holiday" + _description = "beesdoo.shift.holiday" + _inherit = "beesdoo.shift.action_mixin" - holiday_start_day = fields.Date(string="Start date for the holiday", default=fields.Date.today) + holiday_start_day = fields.Date( + string="Start date for the holiday", default=fields.Date.today + ) holiday_end_day = fields.Date(string="End date for the holiday (included)") @api.multi def holidays(self): self = self._check() # maybe a different group - status_id = self.env['cooperative.status'].search([('cooperator_id', '=', self.cooperator_id.id)]) - if status_id.holiday_end_time and status_id.holiday_end_time >= status_id.today: - raise ValidationError(_("You cannot encode new holidays since the previous holidays encoded are not over yet")) - status_id.sudo().write({'holiday_start_time': self.holiday_start_day, 'holiday_end_time': self.holiday_end_day}) - self.env['beesdoo.shift.shift'].sudo().unsubscribe_from_today([self.cooperator_id.id], today=self.holiday_start_day, end_date=self.holiday_end_day) + status_id = self.env["cooperative.status"].search( + [("cooperator_id", "=", self.cooperator_id.id)] + ) + if ( + status_id.holiday_end_time + and status_id.holiday_end_time >= status_id.today + ): + raise ValidationError( + _( + "You cannot encode new holidays since the previous holidays encoded are not over yet" + ) + ) + status_id.sudo().write( + { + "holiday_start_time": self.holiday_start_day, + "holiday_end_time": self.holiday_end_day, + } + ) + self.env["beesdoo.shift.shift"].sudo().unsubscribe_from_today( + [self.cooperator_id.id], + today=self.holiday_start_day, + end_date=self.holiday_end_day, + ) diff --git a/beesdoo_shift/wizard/instanciate_planning.py b/beesdoo_shift/wizard/instanciate_planning.py index 1653ddd..e25c723 100644 --- a/beesdoo_shift/wizard/instanciate_planning.py +++ b/beesdoo_shift/wizard/instanciate_planning.py @@ -1,28 +1,34 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models class InstanciatePlanning(models.TransientModel): - _name = 'beesddoo.shift.generate_planning' - _description = 'beesddoo.shift.generate_planning' + _name = "beesddoo.shift.generate_planning" + _description = "beesddoo.shift.generate_planning" def _get_planning(self): - return self._context.get('active_id') + return self._context.get("active_id") - date_start = fields.Date("First Day of planning (should be monday)", required=True) - planning_id = fields.Many2one('beesdoo.shift.planning', readonly=True, default=_get_planning) + date_start = fields.Date( + "First Day of planning (should be monday)", required=True + ) + planning_id = fields.Many2one( + "beesdoo.shift.planning", readonly=True, default=_get_planning + ) @api.multi def generate_task(self): self.ensure_one() - self = self.with_context(visualize_date=self.date_start, tracking_disable=True) + self = self.with_context( + visualize_date=self.date_start, tracking_disable=True + ) shifts = self.planning_id.task_template_ids._generate_task_day() return { - 'name': _('Generated Shift'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'kanban,calendar,tree,form,pivot', - 'res_model': 'beesdoo.shift.shift', - 'target': 'current', - 'domain': [('id', 'in', shifts.ids)], - 'context' : {'search_default_gb_day': 1} + "name": _("Generated Shift"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "kanban,calendar,tree,form,pivot", + "res_model": "beesdoo.shift.shift", + "target": "current", + "domain": [("id", "in", shifts.ids)], + "context": {"search_default_gb_day": 1}, } diff --git a/beesdoo_shift/wizard/subscribe.py b/beesdoo_shift/wizard/subscribe.py index f2ee8e5..190fa8c 100644 --- a/beesdoo_shift/wizard/subscribe.py +++ b/beesdoo_shift/wizard/subscribe.py @@ -1,86 +1,145 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import UserError + class StatusActionMixin(models.AbstractModel): _name = "beesdoo.shift.action_mixin" _description = "beesdoo.shift.action_mixin" - cooperator_id = fields.Many2one('res.partner', default=lambda self: self.env['res.partner'].browse(self._context.get('active_id')), required=True) + cooperator_id = fields.Many2one( + "res.partner", + default=lambda self: self.env["res.partner"].browse( + self._context.get("active_id") + ), + required=True, + ) - def _check(self, group='beesdoo_shift.group_shift_management'): + def _check(self, group="beesdoo_shift.group_shift_management"): self.ensure_one() if not self.env.user.has_group(group): - raise UserError(_("You don't have the required access for this operation.")) - if self.cooperator_id == self.env.user.partner_id and not self.env.user.has_group('beesdoo_shift.group_cooperative_admin'): + raise UserError( + _("You don't have the required access for this operation.") + ) + if ( + self.cooperator_id == self.env.user.partner_id + and not self.env.user.has_group( + "beesdoo_shift.group_cooperative_admin" + ) + ): raise UserError(_("You cannot perform this operation on yourself")) return self.with_context(real_uid=self._uid) + class Subscribe(models.TransientModel): - _name = 'beesdoo.shift.subscribe' - _description = 'beesdoo.shift.subscribe' - _inherit = 'beesdoo.shift.action_mixin' + _name = "beesdoo.shift.subscribe" + _description = "beesdoo.shift.subscribe" + _inherit = "beesdoo.shift.action_mixin" def _get_date(self): - date = self.env['res.partner'].browse(self._context.get('active_id')).info_session_date + date = ( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .info_session_date + ) if not date: return fields.Date.today() else: return date def _get_info_session_date(self): - date = (self.env['res.partner'] - .browse(self._context.get('active_id')) - .info_session_date) + date = ( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .info_session_date + ) if date and self._get_info_session_followed(): return date else: return False def _get_info_session_followed(self): - session_followed = (self.env['res.partner'] - .browse(self._context.get('active_id')) - .info_session) + session_followed = ( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .info_session + ) return session_followed def _get_shift(self): - shifts = self.env['res.partner'].browse(self._context.get('active_id')).subscribed_shift_ids + shifts = ( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .subscribed_shift_ids + ) if shifts: return shifts[0] return def _get_nb_shifts(self): - return len(self.env['res.partner'].browse(self._context.get('active_id')).subscribed_shift_ids) + return len( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .subscribed_shift_ids + ) def _get_super(self): - return self.env['res.partner'].browse(self._context.get('active_id')).super + return ( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .super + ) def _get_mode(self): - return self.env['res.partner'].browse(self._context.get('active_id')).working_mode + return ( + self.env["res.partner"] + .browse(self._context.get("active_id")) + .working_mode + ) def _get_reset_counter_default(self): - partner = self.env['res.partner'].browse(self._context.get('active_id')) - return partner.state == 'unsubscribed' and partner.working_mode == 'regular' - - info_session = fields.Boolean(string="Followed an information session", default=_get_info_session_followed) - info_session_date = fields.Date(string="Date of information session", default=_get_info_session_date) + partner = self.env["res.partner"].browse( + self._context.get("active_id") + ) + return ( + partner.state == "unsubscribed" + and partner.working_mode == "regular" + ) + + info_session = fields.Boolean( + string="Followed an information session", + default=_get_info_session_followed, + ) + info_session_date = fields.Date( + string="Date of information session", default=_get_info_session_date + ) super = fields.Boolean(string="Super Cooperator", default=_get_super) working_mode = fields.Selection( [ - ('regular', 'Regular worker'), - ('irregular', 'Irregular worker'), - ('exempt', 'Exempted'), - ], default=_get_mode + ("regular", "Regular worker"), + ("irregular", "Irregular worker"), + ("exempt", "Exempted"), + ], + default=_get_mode, + ) + exempt_reason_id = fields.Many2one( + "cooperative.exempt.reason", "Exempt Reason" + ) + shift_id = fields.Many2one("beesdoo.shift.template", default=_get_shift) + nb_shifts = fields.Integer( + string="Number of shifts", default=_get_nb_shifts ) - exempt_reason_id = fields.Many2one('cooperative.exempt.reason', 'Exempt Reason') - shift_id = fields.Many2one('beesdoo.shift.template', default=_get_shift) - nb_shifts = fields.Integer(string='Number of shifts', default=_get_nb_shifts) reset_counter = fields.Boolean(default=_get_reset_counter_default) reset_compensation_counter = fields.Boolean(default=False) - unsubscribed = fields.Boolean(default=False, string="Are you sure to remove this cooperator from his subscribed shift ?") - irregular_start_date = fields.Date(string="Start Date", default=fields.Date.today) - resigning = fields.Boolean(default=False, help="Want to leave the beescoop") - - + unsubscribed = fields.Boolean( + default=False, + string="Are you sure to remove this cooperator from his subscribed shift ?", + ) + irregular_start_date = fields.Date( + string="Start Date", default=fields.Date.today + ) + resigning = fields.Boolean( + default=False, help="Want to leave the beescoop" + ) @api.multi def unsubscribe(self): @@ -88,53 +147,57 @@ class Subscribe(models.TransientModel): if not self.unsubscribed: return - status_id = self.env['cooperative.status'].search([('cooperator_id', '=', self.cooperator_id.id)]) + status_id = self.env["cooperative.status"].search( + [("cooperator_id", "=", self.cooperator_id.id)] + ) data = { - 'unsubscribed': True, - 'cooperator_id': self.cooperator_id.id, - 'resigning': self.resigning, + "unsubscribed": True, + "cooperator_id": self.cooperator_id.id, + "resigning": self.resigning, } if status_id: status_id.sudo().write(data) else: - self.env['cooperative.status'].sudo().create(data) + self.env["cooperative.status"].sudo().create(data) @api.multi def subscribe(self): self = self._check() if self.shift_id and self.shift_id.remaining_worker <= 0: - raise UserError(_('There is no remaining space for this shift')) + raise UserError(_("There is no remaining space for this shift")) if self.shift_id: - #Remove existing shift then subscribe to the new shift - self.cooperator_id.sudo().write({'subscribed_shift_ids' : [(6,0, [self.shift_id.id])]}) - if self.working_mode != 'regular': - #Remove existing shift then subscribe to the new shift - self.cooperator_id.sudo().write({'subscribed_shift_ids': [(5,)]}) - + # Remove existing shift then subscribe to the new shift + self.cooperator_id.sudo().write( + {"subscribed_shift_ids": [(6, 0, [self.shift_id.id])]} + ) + if self.working_mode != "regular": + # Remove existing shift then subscribe to the new shift + self.cooperator_id.sudo().write({"subscribed_shift_ids": [(5,)]}) data = { - 'info_session': self.info_session, - 'info_session_date': self.info_session_date, - 'working_mode': self.working_mode, - 'exempt_reason_id' : self.exempt_reason_id.id, - 'super': self.super, - 'cooperator_id': self.cooperator_id.id, - 'unsubscribed': False, - 'irregular_start_date': self.irregular_start_date, - 'irregular_absence_date': False, - 'irregular_absence_counter': 0, + "info_session": self.info_session, + "info_session_date": self.info_session_date, + "working_mode": self.working_mode, + "exempt_reason_id": self.exempt_reason_id.id, + "super": self.super, + "cooperator_id": self.cooperator_id.id, + "unsubscribed": False, + "irregular_start_date": self.irregular_start_date, + "irregular_absence_date": False, + "irregular_absence_counter": 0, } if self.reset_counter: - data['sr'] = 0 - data['extension_start_time'] = False - data['alert_start_time'] = False - data['time_extension'] = 0 + data["sr"] = 0 + data["extension_start_time"] = False + data["alert_start_time"] = False + data["time_extension"] = 0 if self.reset_compensation_counter: - data['sc'] = 0 + data["sc"] = 0 - coop_status_obj = self.env['cooperative.status'] + coop_status_obj = self.env["cooperative.status"] status_id = coop_status_obj.search( - [('cooperator_id', '=', self.cooperator_id.id)]) + [("cooperator_id", "=", self.cooperator_id.id)] + ) if status_id: status_id.sudo().write(data) else: diff --git a/beesdoo_shift/wizard/temporary_exemption.py b/beesdoo_shift/wizard/temporary_exemption.py index 459379c..2b3f595 100644 --- a/beesdoo_shift/wizard/temporary_exemption.py +++ b/beesdoo_shift/wizard/temporary_exemption.py @@ -1,24 +1,44 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError + class TemporaryExemption(models.TransientModel): - _name = 'beesdoo.shift.temporary_exemption' - _description = 'beesdoo.shift.temporary_exemption' - _inherit = 'beesdoo.shift.action_mixin' + _name = "beesdoo.shift.temporary_exemption" + _description = "beesdoo.shift.temporary_exemption" + _inherit = "beesdoo.shift.action_mixin" - temporary_exempt_reason_id = fields.Many2one('cooperative.exempt.reason', 'Exempt Reason', required=True) - temporary_exempt_start_date = fields.Date(default=fields.Date.today, required=True) + temporary_exempt_reason_id = fields.Many2one( + "cooperative.exempt.reason", "Exempt Reason", required=True + ) + temporary_exempt_start_date = fields.Date( + default=fields.Date.today, required=True + ) temporary_exempt_end_date = fields.Date(required=True) @api.multi def exempt(self): self = self._check() # maybe a different group - status_id = self.env['cooperative.status'].search([('cooperator_id', '=', self.cooperator_id.id)]) - if status_id.temporary_exempt_end_date and status_id.temporary_exempt_end_date >= status_id.today: - raise ValidationError(_("You cannot encode new temporary exemptuon since the previous one are not over yet")) - status_id.sudo().write({ - 'temporary_exempt_start_date': self.temporary_exempt_start_date, - 'temporary_exempt_end_date': self.temporary_exempt_end_date, - 'temporary_exempt_reason_id': self.temporary_exempt_reason_id.id, - }) - self.env['beesdoo.shift.shift'].sudo().unsubscribe_from_today([self.cooperator_id.id], today=self.temporary_exempt_start_date, end_date=self.temporary_exempt_end_date) + status_id = self.env["cooperative.status"].search( + [("cooperator_id", "=", self.cooperator_id.id)] + ) + if ( + status_id.temporary_exempt_end_date + and status_id.temporary_exempt_end_date >= status_id.today + ): + raise ValidationError( + _( + "You cannot encode new temporary exemptuon since the previous one are not over yet" + ) + ) + status_id.sudo().write( + { + "temporary_exempt_start_date": self.temporary_exempt_start_date, + "temporary_exempt_end_date": self.temporary_exempt_end_date, + "temporary_exempt_reason_id": self.temporary_exempt_reason_id.id, + } + ) + self.env["beesdoo.shift.shift"].sudo().unsubscribe_from_today( + [self.cooperator_id.id], + today=self.temporary_exempt_start_date, + end_date=self.temporary_exempt_end_date, + ) diff --git a/beesdoo_shift_attendance/__manifest__.py b/beesdoo_shift_attendance/__manifest__.py index 6b90577..6675638 100644 --- a/beesdoo_shift_attendance/__manifest__.py +++ b/beesdoo_shift_attendance/__manifest__.py @@ -4,31 +4,25 @@ # this module can be splitted into a generic part, and a specific part # that implement the worker_status rules. { - 'name': "Beescoop Shift Attendance Sheet", - - 'summary': """ + "name": "Beescoop Shift Attendance Sheet", + "summary": """ Volonteer Timetable Management Attendance Sheet for BEES coop""", - - 'description': """ + "description": """ """, - - 'author': "Elouan Le Bars, Coop It Easy", - 'website': "https://github.com/beescoop/Obeesdoo", - - 'category': 'Cooperative management', - 'version': '12.0.1.0.1', - - 'depends': [ - 'beesdoo_base', - 'beesdoo_shift', - 'beesdoo_worker_status', - 'mail', - 'barcodes', + "author": "Elouan Le Bars, Coop It Easy", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Cooperative management", + "version": "12.0.1.0.1", + "depends": [ + "beesdoo_base", + "beesdoo_shift", + "beesdoo_worker_status", + "mail", + "barcodes", ], - - 'data': [ + "data": [ "data/system_parameter.xml", "data/cron.xml", "data/mail_template.xml", @@ -39,7 +33,5 @@ "wizard/generate_missing_attendance_sheets.xml", "views/attendance_sheet.xml", ], - 'demo': [ - "demo/users.xml", - ] + "demo": ["demo/users.xml",], } diff --git a/beesdoo_shift_attendance/models/attendance_sheet.py b/beesdoo_shift_attendance/models/attendance_sheet.py index df8669e..9e40963 100644 --- a/beesdoo_shift_attendance/models/attendance_sheet.py +++ b/beesdoo_shift_attendance/models/attendance_sheet.py @@ -16,6 +16,7 @@ class AttendanceSheetShift(models.Model): but create() method from res.partner raise error when class is Abstract. """ + _name = "beesdoo.shift.sheet.shift" _description = "Copy of an actual shift into an attendance sheet" _order = "task_type_id, worker_name" @@ -61,7 +62,9 @@ class AttendanceSheetShift(models.Model): ) worker_name = fields.Char(related="worker_id.name", store=True) task_type_id = fields.Many2one( - "beesdoo.shift.type", string="Task Type", default=pre_filled_task_type_id + "beesdoo.shift.type", + string="Task Type", + default=pre_filled_task_type_id, ) working_mode = fields.Selection( related="worker_id.working_mode", string="Working Mode" @@ -120,10 +123,7 @@ class AttendanceSheetShiftAdded(models.Model): class AttendanceSheet(models.Model): _name = "beesdoo.shift.sheet" - _inherit = [ - "mail.thread", - "barcodes.barcode_events_mixin", - ] + _inherit = ["mail.thread", "barcodes.barcode_events_mixin"] _description = "Attendance sheet" _order = "start_time" @@ -136,7 +136,7 @@ class AttendanceSheet(models.Model): ) active = fields.Boolean(string="Active", default=1) state = fields.Selection( - [("not_validated", "Not Validated"), ("validated", "Validated"),], + [("not_validated", "Not Validated"), ("validated", "Validated")], string="State", readonly=True, index=True, @@ -175,9 +175,7 @@ class AttendanceSheet(models.Model): help="Indicative maximum number of workers.", ) attended_worker_no = fields.Integer( - string="Number of workers present", - default=0, - readonly=True, + string="Number of workers present", default=0, readonly=True ) notes = fields.Text( "Notes", @@ -233,9 +231,7 @@ class AttendanceSheet(models.Model): start_time = fields.Datetime.context_timestamp(rec, rec.start_time) end_time = fields.Datetime.context_timestamp(rec, rec.end_time) rec.time_slot = ( - start_time.strftime("%H:%M") - + "-" - + end_time.strftime("%H:%M") + start_time.strftime("%H:%M") + "-" + end_time.strftime("%H:%M") ) @api.depends("start_time", "end_time", "week", "day_abbrevation") @@ -319,10 +315,14 @@ class AttendanceSheet(models.Model): ) def on_barcode_scanned(self, barcode): - if self.env.user.has_group("beesdoo_shift_attendance.group_shift_attendance"): + if self.env.user.has_group( + "beesdoo_shift_attendance.group_shift_attendance" + ): raise UserError( - _("You must be logged as 'Attendance Sheet Generic Access' " - " if you want to scan cards.") + _( + "You must be logged as 'Attendance Sheet Generic Access' " + " if you want to scan cards." + ) ) if self.state == "validated": @@ -370,7 +370,9 @@ class AttendanceSheet(models.Model): ) if worker.working_mode not in ("regular", "irregular"): raise UserError( - _("%s's working mode is %s and should be regular or irregular.") + _( + "%s's working mode is %s and should be regular or irregular." + ) % (worker.name, worker.working_mode) ) @@ -428,7 +430,11 @@ class AttendanceSheet(models.Model): for task in tasks: # Only one shift is added if multiple similar exist - if task.worker_id and task.worker_id not in workers and (task.state != "cancel") : + if ( + task.worker_id + and task.worker_id not in workers + and (task.state != "cancel") + ): expected_shift.create( { "attendance_sheet_id": new_sheet.id, @@ -468,7 +474,8 @@ class AttendanceSheet(models.Model): if expected_shift.state != "done": mail_template = self.env.ref( - "beesdoo_shift_attendance.email_template_non_attendance", False + "beesdoo_shift_attendance.email_template_non_attendance", + False, ) mail_template.send_mail(expected_shift.task_id.id, True) @@ -609,7 +616,9 @@ class AttendanceSheet(models.Model): sheets = self.env["beesdoo.shift.sheet"] current_time = datetime.now() generation_interval_setting = int( - self.env["ir.config_parameter"].sudo().get_param( + self.env["ir.config_parameter"] + .sudo() + .get_param( "beesdoo_shift_attendance.attendance_sheet_generation_interval" ) ) diff --git a/beesdoo_shift_attendance/models/res_config_settings.py b/beesdoo_shift_attendance/models/res_config_settings.py index ca426ab..3c32859 100644 --- a/beesdoo_shift_attendance/models/res_config_settings.py +++ b/beesdoo_shift_attendance/models/res_config_settings.py @@ -3,7 +3,7 @@ import ast -from odoo import fields, models, api +from odoo import api, fields, models class ResConfigSettings(models.TransientModel): @@ -46,6 +46,6 @@ class ResConfigSettings(models.TransientModel): self.env["ir.config_parameter"].get_param( "beesdoo_shift_attendance.pre_filled_task_type_id" ) - ), + ) ) return res diff --git a/beesdoo_shift_attendance/tests/test_beesdoo_shift.py b/beesdoo_shift_attendance/tests/test_beesdoo_shift.py index e4b4656..d7c5ac2 100644 --- a/beesdoo_shift_attendance/tests/test_beesdoo_shift.py +++ b/beesdoo_shift_attendance/tests/test_beesdoo_shift.py @@ -20,8 +20,10 @@ class TestBeesdooShift(TransactionCase): ] self.shift_expected_model = self.env["beesdoo.shift.sheet.expected"] self.shift_added_model = self.env["beesdoo.shift.sheet.added"] - self.pre_filled_task_type_id = self.env["ir.config_parameter"].sudo().get_param( - "beesdoo_shift.pre_filled_task_type_id" + self.pre_filled_task_type_id = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("beesdoo_shift.pre_filled_task_type_id") ) self.current_time = datetime.now() @@ -67,12 +69,10 @@ class TestBeesdooShift(TransactionCase): ) self.task_template_1 = self.env.ref( - "beesdoo_worker_status" - ".beesdoo_shift_task_template_1_demo" + "beesdoo_worker_status" ".beesdoo_shift_task_template_1_demo" ) self.task_template_2 = self.env.ref( - "beesdoo_worker_status" - ".beesdoo_shift_task_template_2_demo" + "beesdoo_worker_status" ".beesdoo_shift_task_template_2_demo" ) # Set time in and out of generation interval parameter @@ -207,9 +207,7 @@ class TestBeesdooShift(TransactionCase): # Test consistency with actual shift for sheet 1 for shift in sheet_1.expected_shift_ids: self.assertEquals(shift.worker_id, shift.task_id.worker_id) - self.assertEquals( - shift.replaced_id, shift.task_id.replaced_id - ) + self.assertEquals(shift.replaced_id, shift.task_id.replaced_id) self.assertEqual(shift.task_type_id, shift.task_id.task_type_id) self.assertEqual(shift.super_coop_id, shift.task_id.super_coop_id) self.assertEqual(shift.working_mode, shift.task_id.working_mode) @@ -239,7 +237,7 @@ class TestBeesdooShift(TransactionCase): self.attendance_sheet_model.sudo( self.user_generic )._generate_attendance_sheet() - sheet_1 = self.search_sheets(self.start_in_1, self.end_in_1,) + sheet_1 = self.search_sheets(self.start_in_1, self.end_in_1) sheet_1 = sheet_1.sudo(self.user_generic) """ @@ -352,7 +350,9 @@ class TestBeesdooShift(TransactionCase): if waiting_time > 0: with self.assertRaises(UserError) as econtext: sheet_1.validate_with_checks() - self.assertIn("once the shifts have started", str(econtext.exception)) + self.assertIn( + "once the shifts have started", str(econtext.exception) + ) time.sleep(waiting_time) sheet_1.worker_nb_feedback = "enough" diff --git a/beesdoo_shift_attendance/wizard/generate_missing_attendance_sheets.py b/beesdoo_shift_attendance/wizard/generate_missing_attendance_sheets.py index b5394a3..33539fd 100644 --- a/beesdoo_shift_attendance/wizard/generate_missing_attendance_sheets.py +++ b/beesdoo_shift_attendance/wizard/generate_missing_attendance_sheets.py @@ -1,8 +1,8 @@ -from odoo import models, fields, api, _ -from odoo.exceptions import UserError, ValidationError - from datetime import datetime +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + class GenerateMissingAttendanceSheets(models.TransientModel): """ @@ -34,7 +34,7 @@ class GenerateMissingAttendanceSheets(models.TransientModel): start_time = task.start_time end_time = task.end_time sheet = sheets.search( - [("start_time", "=", start_time), ("end_time", "=", end_time),] + [("start_time", "=", start_time), ("end_time", "=", end_time)] ) if not sheet: diff --git a/beesdoo_shift_attendance/wizard/validate_attendance_sheet.py b/beesdoo_shift_attendance/wizard/validate_attendance_sheet.py index e9a6db4..2cbb226 100644 --- a/beesdoo_shift_attendance/wizard/validate_attendance_sheet.py +++ b/beesdoo_shift_attendance/wizard/validate_attendance_sheet.py @@ -1,4 +1,3 @@ - import ast from odoo import _, api, exceptions, fields, models @@ -21,9 +20,9 @@ class ValidateAttendanceSheet(models.TransientModel): def _get_card_support_setting(self): return ast.literal_eval( - self.env["ir.config_parameter"].sudo().get_param( - "beesdoo_shift_attendance.card_support" - ) + self.env["ir.config_parameter"] + .sudo() + .get_param("beesdoo_shift_attendance.card_support") ) @api.multi diff --git a/beesdoo_stock/__manifest__.py b/beesdoo_stock/__manifest__.py index aa41105..471c71a 100644 --- a/beesdoo_stock/__manifest__.py +++ b/beesdoo_stock/__manifest__.py @@ -4,17 +4,13 @@ { "name": "BEES coop Stock", "version": "12.0.1.0.0", - "depends": [ - 'stock', - ], + "depends": ["stock"], "author": "Coop IT Easy SCRLfs", "license": "AGPL-3", "website": "www.coopiteasy.be", "description": """ Enable action on multiple products of a stock receipt """, - "data": [ - 'views/stock_view.xml', - ], - 'installable': True, + "data": ["views/stock_view.xml"], + "installable": True, } diff --git a/beesdoo_stock/models/stock.py b/beesdoo_stock/models/stock.py index 6139855..836e2b2 100644 --- a/beesdoo_stock/models/stock.py +++ b/beesdoo_stock/models/stock.py @@ -2,27 +2,27 @@ from odoo import api, fields, models class StockPackOperation(models.Model): - _inherit = 'stock.picking' + _inherit = "stock.picking" @api.multi def actions_on_articles(self): ids = self._ids context = self._context ctx = (context or {}).copy() - ctx['articles'] = [] + ctx["articles"] = [] for line in self.browse(ids).move_line_ids: - ctx['articles'].append(line.product_id.product_tmpl_id.id) - if ctx['articles']: + ctx["articles"].append(line.product_id.product_tmpl_id.id) + if ctx["articles"]: return { - 'name': 'Articles', - 'view_type': 'list', - 'view_mode': 'list', - 'res_model': 'product.template', - 'view_id': False, - 'target': 'current', - 'type': 'ir.actions.act_window', - 'context': ctx, - 'nodestroy': True, - 'res_id': ctx['articles'], - 'domain': [('id', 'in', ctx['articles'])], + "name": "Articles", + "view_type": "list", + "view_mode": "list", + "res_model": "product.template", + "view_id": False, + "target": "current", + "type": "ir.actions.act_window", + "context": ctx, + "nodestroy": True, + "res_id": ctx["articles"], + "domain": [("id", "in", ctx["articles"])], } diff --git a/beesdoo_stock_coverage/models/product_template.py b/beesdoo_stock_coverage/models/product_template.py index 4af6842..f890269 100644 --- a/beesdoo_stock_coverage/models/product_template.py +++ b/beesdoo_stock_coverage/models/product_template.py @@ -2,7 +2,7 @@ # Robin Keunen # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError diff --git a/beesdoo_stock_coverage/readme/CONTRIBUTORS.rst b/beesdoo_stock_coverage/readme/CONTRIBUTORS.rst index 1798654..7932f93 100644 --- a/beesdoo_stock_coverage/readme/CONTRIBUTORS.rst +++ b/beesdoo_stock_coverage/readme/CONTRIBUTORS.rst @@ -1,2 +1 @@ * Robin Keunen - diff --git a/beesdoo_stock_coverage/tests/test_stock_coverage.py b/beesdoo_stock_coverage/tests/test_stock_coverage.py index 8719d60..6bb4014 100644 --- a/beesdoo_stock_coverage/tests/test_stock_coverage.py +++ b/beesdoo_stock_coverage/tests/test_stock_coverage.py @@ -3,10 +3,11 @@ # @author: Robin Keunen # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from datetime import timedelta + from odoo import fields -from odoo.tools import float_compare from odoo.tests.common import TransactionCase -from datetime import timedelta +from odoo.tools import float_compare class TestModule(TransactionCase): diff --git a/beesdoo_website_eater/__manifest__.py b/beesdoo_website_eater/__manifest__.py index 2fb3559..1990446 100644 --- a/beesdoo_website_eater/__manifest__.py +++ b/beesdoo_website_eater/__manifest__.py @@ -2,28 +2,17 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'BEES coop Website Eater', - - 'summary': """ + "name": "BEES coop Website Eater", + "summary": """ Show the eaters of a cooperator in the website portal. """, - 'description': """ + "description": """ """, - - 'author': 'Rémy Taymans', - 'license': 'AGPL-3', - 'version': '12.0.1.0.0', - 'website': "https://github.com/beescoop/Obeesdoo", - - 'category': 'Website', - - 'depends': [ - 'website', - 'portal', - 'beesdoo_base', - ], - - 'data': [ - 'views/beesdoo_website_eater_templates.xml', - ] + "author": "Rémy Taymans", + "license": "AGPL-3", + "version": "12.0.1.0.0", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Website", + "depends": ["website", "portal", "beesdoo_base"], + "data": ["views/beesdoo_website_eater_templates.xml"], } diff --git a/beesdoo_website_eater/controllers/main.py b/beesdoo_website_eater/controllers/main.py index e7c21f4..1827e6c 100644 --- a/beesdoo_website_eater/controllers/main.py +++ b/beesdoo_website_eater/controllers/main.py @@ -8,12 +8,10 @@ from odoo.addons.portal.controllers.portal import CustomerPortal class EaterWebsiteAccount(CustomerPortal): - def _prepare_portal_layout_values(self): - values = super(EaterWebsiteAccount, - self)._prepare_portal_layout_values() + values = super( + EaterWebsiteAccount, self + )._prepare_portal_layout_values() partner = request.env.user.partner_id.commercial_partner_id - values.update({ - 'eaters': partner.child_eater_ids, - }) + values.update({"eaters": partner.child_eater_ids}) return values diff --git a/beesdoo_website_posorder_amount/controllers/main.py b/beesdoo_website_posorder_amount/controllers/main.py index 7e886ce..9e2654d 100644 --- a/beesdoo_website_posorder_amount/controllers/main.py +++ b/beesdoo_website_posorder_amount/controllers/main.py @@ -2,22 +2,30 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.addons.portal.controllers.portal import CustomerPortal from odoo.http import request +from odoo.addons.portal.controllers.portal import CustomerPortal + class PortalPosOrderAmount(CustomerPortal): - def _prepare_portal_layout_values(self): values = super( PortalPosOrderAmount, self )._prepare_portal_layout_values() user = request.env.user - owned_posorder = request.env["pos.order"].sudo().search( - [ - ("partner_id", "=", user.partner_id.commercial_partner_id.id), - ("state", "!=", "cancel"), - ] + owned_posorder = ( + request.env["pos.order"] + .sudo() + .search( + [ + ( + "partner_id", + "=", + user.partner_id.commercial_partner_id.id, + ), + ("state", "!=", "cancel"), + ] + ) ) values["posorder_amount"] = sum( po.amount_total for po in owned_posorder diff --git a/beesdoo_website_shift/__manifest__.py b/beesdoo_website_shift/__manifest__.py index 08fbdf7..a8a8f47 100644 --- a/beesdoo_website_shift/__manifest__.py +++ b/beesdoo_website_shift/__manifest__.py @@ -3,13 +3,13 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'BEES coop Website Shift', - 'summary': """ + "name": "BEES coop Website Shift", + "summary": """ Show available shifts for regular and irregular workers on the website and let workers manage their shifts with an easy web interface. """, - 'description': """ + "description": """ """, "author": "Coop IT Easy SCRLfs", "license": "AGPL-3", diff --git a/beesdoo_website_shift/controllers/main.py b/beesdoo_website_shift/controllers/main.py index 2af24fb..42cb337 100644 --- a/beesdoo_website_shift/controllers/main.py +++ b/beesdoo_website_shift/controllers/main.py @@ -6,39 +6,41 @@ from ast import literal_eval from datetime import datetime, timedelta from itertools import groupby + from pytz import timezone, utc -from odoo import http, fields +from odoo import fields, http from odoo.http import request from odoo.addons.beesdoo_shift.models.planning import float_to_time class WebsiteShiftController(http.Controller): - def is_user_worker(self): - user = request.env['res.users'].browse(request.uid) + user = request.env["res.users"].browse(request.uid) return user.partner_id.is_worker def is_user_irregular(self): - user = request.env['res.users'].browse(request.uid) + user = request.env["res.users"].browse(request.uid) working_mode = user.partner_id.working_mode - return working_mode == 'irregular' + return working_mode == "irregular" def is_user_regular(self): - user = request.env['res.users'].browse(request.uid) + user = request.env["res.users"].browse(request.uid) working_mode = user.partner_id.working_mode - return working_mode == 'regular' + return working_mode == "regular" def is_user_regular_without_shift(self): - user = request.env['res.users'].browse(request.uid) - return (not user.partner_id.subscribed_shift_ids.id - and self.is_user_regular()) + user = request.env["res.users"].browse(request.uid) + return ( + not user.partner_id.subscribed_shift_ids.id + and self.is_user_regular() + ) def is_user_exempted(self): - user = request.env['res.users'].browse(request.uid) + user = request.env["res.users"].browse(request.uid) working_mode = user.partner_id.working_mode - return working_mode == 'exempt' + return working_mode == "exempt" def user_can_subscribe(self, user=None): """Return True if a user can subscribe to a shift. A user can @@ -48,10 +50,12 @@ class WebsiteShiftController(http.Controller): * the user is not resigning """ if not user: - user = request.env['res.users'].browse(request.uid) - return (user.partner_id.working_mode == 'irregular' - and user.partner_id.state != 'unsubscribed' - and user.partner_id.state != 'resigning') + user = request.env["res.users"].browse(request.uid) + return ( + user.partner_id.working_mode == "irregular" + and user.partner_id.state != "unsubscribed" + and user.partner_id.state != "resigning" + ) def add_days(self, datetime, days): """ @@ -66,12 +70,12 @@ class WebsiteShiftController(http.Controller): assert datetime.tzinfo is None # Get current user and user timezone # Take user tz, if empty use context tz, if empty use UTC - cur_user = request.env['res.users'].browse(request.uid) + cur_user = request.env["res.users"].browse(request.uid) user_tz = utc if cur_user.tz: user_tz = timezone(cur_user.tz) - elif request.env.context['tz']: - user_tz = timezone(request.env.context['tz']) + elif request.env.context["tz"]: + user_tz = timezone(request.env.context["tz"]) # Convert to UTC dt_utc = utc.localize(datetime, is_dst=False) # Convert to user TZ @@ -86,43 +90,39 @@ class WebsiteShiftController(http.Controller): newdt_utc = newdt_local.astimezone(utc) return newdt_utc.replace(tzinfo=None) - @http.route('/my/shift', auth='user', website=True) + @http.route("/my/shift", auth="user", website=True) def my_shift(self, **kw): """ Personal page for managing your shifts """ if self.is_user_irregular(): return request.render( - 'beesdoo_website_shift.my_shift_irregular_worker', - self.my_shift_irregular_worker(nexturl='/my/shift') + "beesdoo_website_shift.my_shift_irregular_worker", + self.my_shift_irregular_worker(nexturl="/my/shift"), ) if self.is_user_regular_without_shift(): return request.render( - 'beesdoo_website_shift.my_shift_regular_worker_without_shift', - self.my_shift_regular_worker_without_shift() + "beesdoo_website_shift.my_shift_regular_worker_without_shift", + self.my_shift_regular_worker_without_shift(), ) if self.is_user_regular(): return request.render( - 'beesdoo_website_shift.my_shift_regular_worker', - self.my_shift_regular_worker() + "beesdoo_website_shift.my_shift_regular_worker", + self.my_shift_regular_worker(), ) if self.is_user_exempted(): return request.render( - 'beesdoo_website_shift.my_shift_exempted_worker', - self.my_shift_exempted_worker() + "beesdoo_website_shift.my_shift_exempted_worker", + self.my_shift_exempted_worker(), ) if self.is_user_worker(): return request.render( - 'beesdoo_website_shift.my_shift_new_worker', - {} + "beesdoo_website_shift.my_shift_new_worker", {} ) - return request.render( - 'beesdoo_website_shift.my_shift_non_worker', - {} - ) + return request.render("beesdoo_website_shift.my_shift_non_worker", {}) - @http.route('/shift//subscribe', auth='user', website=True) + @http.route("/shift//subscribe", auth="user", website=True) def subscribe_to_shift(self, shift_id=-1, **kw): """ Subscribe the current connected user into the given shift @@ -136,73 +136,74 @@ class WebsiteShiftController(http.Controller): for attendance sheet generation defined in beesdoo_shift settings """ # Get current user - cur_user = request.env['res.users'].browse(request.uid) + cur_user = request.env["res.users"].browse(request.uid) # Get the shift - shift = request.env['beesdoo.shift.shift'].sudo().browse(shift_id) + shift = request.env["beesdoo.shift.shift"].sudo().browse(shift_id) # Get config irregular_enable_sign_up = request.website.irregular_enable_sign_up # Set start time limit as defined in beesdoo_shift settings # TODO: Move this into the attendance_sheet module # setting = request.website.attendance_sheet_generation_interval start_time_limit = datetime.now() # + timedelta(minutes=setting) - request.session['success'] = False - - if (irregular_enable_sign_up - and self.user_can_subscribe() - and shift - and shift.state == "open" - and shift.start_time > start_time_limit - and not shift.worker_id): + request.session["success"] = False + + if ( + irregular_enable_sign_up + and self.user_can_subscribe() + and shift + and shift.state == "open" + and shift.start_time > start_time_limit + and not shift.worker_id + ): shift.worker_id = cur_user.partner_id - request.session['success'] = True - return request.redirect(kw['nexturl']) + request.session["success"] = True + return request.redirect(kw["nexturl"]) - @http.route('/shift_irregular_worker', auth='public', website=True) + @http.route("/shift_irregular_worker", auth="public", website=True) def public_shift_irregular_worker(self, **kw): """ Show a public access page that show all the available shifts for irregular worker. """ - nexturl = '/shift_irregular_worker' + nexturl = "/shift_irregular_worker" irregular_enable_sign_up = False # Create template context template_context = {} - template_context.update(self.available_shift_irregular_worker( - irregular_enable_sign_up, nexturl - )) + template_context.update( + self.available_shift_irregular_worker( + irregular_enable_sign_up, nexturl + ) + ) return request.render( - 'beesdoo_website_shift.public_shift_irregular_worker', - template_context + "beesdoo_website_shift.public_shift_irregular_worker", + template_context, ) - @http.route('/shift_template_regular_worker', auth='public', website=True) + @http.route("/shift_template_regular_worker", auth="public", website=True) def public_shift_template_regular_worker(self, **kw): """ Show a public access page that show all the available shift templates for regular worker. """ # Get all the task template - template = request.env['beesdoo.shift.template'] - task_templates = template.sudo().search([], order="planning_id, day_nb_id, start_time") + template = request.env["beesdoo.shift.template"] + task_templates = template.sudo().search( + [], order="planning_id, day_nb_id, start_time" + ) # Get config regular_highlight_rule = request.website.regular_highlight_rule task_tpls_data = [] for task_tpl in task_templates: - has_enough_workers = ( - task_tpl.remaining_worker <= ( - task_tpl.worker_nb * regular_highlight_rule / 100 - ) + has_enough_workers = task_tpl.remaining_worker <= ( + task_tpl.worker_nb * regular_highlight_rule / 100 ) task_tpls_data.append((task_tpl, has_enough_workers)) return request.render( - 'beesdoo_website_shift.public_shift_template_regular_worker', - { - 'task_tpls_data': task_tpls_data, - 'float_to_time': float_to_time, - } + "beesdoo_website_shift.public_shift_template_regular_worker", + {"task_tpls_data": task_tpls_data, "float_to_time": float_to_time}, ) def my_shift_irregular_worker(self, nexturl=""): @@ -218,16 +219,18 @@ class WebsiteShiftController(http.Controller): template_context.update(self.my_shift_worker_status()) template_context.update(self.my_shift_next_shifts()) template_context.update(self.my_shift_past_shifts()) - template_context.update(self.available_shift_irregular_worker( - irregular_enable_sign_up and self.user_can_subscribe(), nexturl - )) + template_context.update( + self.available_shift_irregular_worker( + irregular_enable_sign_up and self.user_can_subscribe(), nexturl + ) + ) # Add feedback about the success or the fail of the subscription - template_context['back_from_subscription'] = False - if 'success' in request.session: - template_context['back_from_subscription'] = True - template_context['success'] = request.session.get('success') - del request.session['success'] + template_context["back_from_subscription"] = False + if "success" in request.session: + template_context["back_from_subscription"] = True + template_context["success"] = request.session.get("success") + del request.session["success"] # Add setting for subscription allowed time # TODO: move this to the attendance_sheet module @@ -235,7 +238,7 @@ class WebsiteShiftController(http.Controller): # request.website.attendance_sheet_generation_interval # ) subscription_time_limit = 0 - template_context['subscription_time_limit'] = subscription_time_limit + template_context["subscription_time_limit"] = subscription_time_limit return template_context @@ -253,17 +256,16 @@ class WebsiteShiftController(http.Controller): template_context = {} # Get all the task template - template = request.env['beesdoo.shift.template'] - task_templates = template.sudo().search([], order="planning_id, day_nb_id, start_time") + template = request.env["beesdoo.shift.template"] + task_templates = template.sudo().search( + [], order="planning_id, day_nb_id, start_time" + ) template_context.update(self.my_shift_worker_status()) template_context.update(self.my_shift_next_shifts()) template_context.update(self.my_shift_past_shifts()) template_context.update( - { - 'task_templates': task_templates, - 'float_to_time': float_to_time, - } + {"task_templates": task_templates, "float_to_time": float_to_time} ) return template_context @@ -273,29 +275,42 @@ class WebsiteShiftController(http.Controller): """ return self.my_shift_worker_status() - def available_shift_irregular_worker(self, irregular_enable_sign_up=False, - nexturl=""): + def available_shift_irregular_worker( + self, irregular_enable_sign_up=False, nexturl="" + ): """ Return template variables for 'beesdoo_website_shift.available_shift_irregular_worker' template """ # Get current user - cur_user = request.env['res.users'].browse(request.uid) + cur_user = request.env["res.users"].browse(request.uid) # Get all the shifts in the future with no worker now = datetime.now() - shifts = request.env['beesdoo.shift.shift'].sudo().search( - [('start_time', '>', now.strftime("%Y-%m-%d %H:%M:%S")), - ('worker_id', '=', False), - ('state', '=', 'open')], - order="start_time, task_template_id, task_type_id", + shifts = ( + request.env["beesdoo.shift.shift"] + .sudo() + .search( + [ + ("start_time", ">", now.strftime("%Y-%m-%d %H:%M:%S")), + ("worker_id", "=", False), + ("state", "=", "open"), + ], + order="start_time, task_template_id, task_type_id", + ) ) # Get shifts where user is subscribed - subscribed_shifts = request.env['beesdoo.shift.shift'].sudo().search( - [('start_time', '>', now.strftime("%Y-%m-%d %H:%M:%S")), - ('worker_id', '=', cur_user.partner_id.id)], - order="start_time, task_template_id, task_type_id", + subscribed_shifts = ( + request.env["beesdoo.shift.shift"] + .sudo() + .search( + [ + ("start_time", ">", now.strftime("%Y-%m-%d %H:%M:%S")), + ("worker_id", "=", cur_user.partner_id.id), + ], + order="start_time, task_template_id, task_type_id", + ) ) # Get config @@ -308,7 +323,7 @@ class WebsiteShiftController(http.Controller): # task_type groupby_iter = groupby( shifts, - lambda s: (s.task_template_id, s.start_time, s.task_type_id) + lambda s: (s.task_template_id, s.start_time, s.task_type_id), ) shifts_count_subscribed = [] @@ -321,29 +336,39 @@ class WebsiteShiftController(http.Controller): free_space = len(shift_list) # Is the current user subscribed to this task_template is_subscribed = any( - (sub_shift.task_template_id == task_template and - sub_shift.start_time == start_time and - sub_shift.task_type_id == task_type) - for sub_shift in subscribed_shifts) + ( + sub_shift.task_template_id == task_template + and sub_shift.start_time == start_time + and sub_shift.task_type_id == task_type + ) + for sub_shift in subscribed_shifts + ) # Check the necessary number of worker based on the # highlight_rule_pc - has_enough_workers = free_space <= (task_template.worker_nb - * highlight_rule_pc) / 100 + has_enough_workers = ( + free_space + <= (task_template.worker_nb * highlight_rule_pc) / 100 + ) if free_space >= task_template.worker_nb * hide_rule: - shifts_count_subscribed.append([ - shift_list[0], - free_space, - is_subscribed, - has_enough_workers, - ]) + shifts_count_subscribed.append( + [ + shift_list[0], + free_space, + is_subscribed, + has_enough_workers, + ] + ) # Stop showing shifts if the limit is reached - if irregular_shift_limit > 0 and nb_displayed_shift >= irregular_shift_limit: + if ( + irregular_shift_limit > 0 + and nb_displayed_shift >= irregular_shift_limit + ): break return { - 'shift_templates': shifts_count_subscribed, - 'nexturl': nexturl, - 'irregular_enable_sign_up': irregular_enable_sign_up, + "shift_templates": shifts_count_subscribed, + "nexturl": nexturl, + "irregular_enable_sign_up": irregular_enable_sign_up, } def my_shift_next_shifts(self): @@ -351,13 +376,19 @@ class WebsiteShiftController(http.Controller): Return template variables for 'beesdoo_website_shift.my_shift_next_shifts' template """ # Get current user - cur_user = request.env['res.users'].browse(request.uid) + cur_user = request.env["res.users"].browse(request.uid) # Get shifts where user is subscribed now = datetime.now() - subscribed_shifts_rec = request.env['beesdoo.shift.shift'].sudo().search( - [('start_time', '>', now.strftime("%Y-%m-%d %H:%M:%S")), - ('worker_id', '=', cur_user.partner_id.id)], - order="start_time, task_template_id, task_type_id", + subscribed_shifts_rec = ( + request.env["beesdoo.shift.shift"] + .sudo() + .search( + [ + ("start_time", ">", now.strftime("%Y-%m-%d %H:%M:%S")), + ("worker_id", "=", cur_user.partner_id.id), + ], + order="start_time, task_template_id, task_type_id", + ) ) # Create a list of record in order to add new record to it later subscribed_shifts = [] @@ -372,22 +403,34 @@ class WebsiteShiftController(http.Controller): if nb_subscribed_shifts > 0: main_shift = subscribed_shifts[-1] else: - task_template = request.env['beesdoo.shift.template'].sudo().search( - [('worker_ids', 'in', cur_user.partner_id.id)], - limit=1, + task_template = ( + request.env["beesdoo.shift.template"] + .sudo() + .search( + [("worker_ids", "in", cur_user.partner_id.id)], limit=1 + ) ) - main_shift = request.env['beesdoo.shift.shift'].sudo().search( - [('task_template_id', '=', task_template[0].id), - ('start_time', '!=', False), - ('end_time', '!=', False)], - order="start_time desc", - limit=1, + main_shift = ( + request.env["beesdoo.shift.shift"] + .sudo() + .search( + [ + ("task_template_id", "=", task_template[0].id), + ("start_time", "!=", False), + ("end_time", "!=", False), + ], + order="start_time desc", + limit=1, + ) ) # Get config regular_next_shift_limit = request.website.regular_next_shift_limit - shift_period = int(request.env['ir.config_parameter'].get_param( - 'beesdoo_website_shift.shift_period')) + shift_period = int( + request.env["ir.config_parameter"].get_param( + "beesdoo_website_shift.shift_period" + ) + ) for i in range(nb_subscribed_shifts, regular_next_shift_limit): # Create the fictive shift @@ -405,19 +448,17 @@ class WebsiteShiftController(http.Controller): shift.revert_info = main_shift.revert_info # Set new date shift.start_time = self.add_days( - main_shift.start_time, - days=i * shift_period + main_shift.start_time, days=i * shift_period ) shift.end_time = self.add_days( - main_shift.end_time, - days=i * shift_period + main_shift.end_time, days=i * shift_period ) # Add the fictive shift to the list of shift subscribed_shifts.append(shift) return { - 'is_regular': self.is_user_regular(), - 'subscribed_shifts': subscribed_shifts, + "is_regular": self.is_user_regular(), + "subscribed_shifts": subscribed_shifts, } def my_shift_past_shifts(self): @@ -425,7 +466,7 @@ class WebsiteShiftController(http.Controller): Return template variables for 'beesdoo_website_shift.my_shift_past_shifts' template """ # Get current user - cur_user = request.env['res.users'].browse(request.uid) + cur_user = request.env["res.users"].browse(request.uid) # Get config past_shift_limit = 0 if self.is_user_irregular(): @@ -435,28 +476,44 @@ class WebsiteShiftController(http.Controller): # Get shifts where user was subscribed now = datetime.now() if past_shift_limit > 0: - past_shifts = request.env['beesdoo.shift.shift'].sudo().search( - [('start_time', '<=', now.strftime("%Y-%m-%d %H:%M:%S")), - ('worker_id', '=', cur_user.partner_id.id)], - order="start_time desc, task_template_id, task_type_id", - limit=past_shift_limit, + past_shifts = ( + request.env["beesdoo.shift.shift"] + .sudo() + .search( + [ + ( + "start_time", + "<=", + now.strftime("%Y-%m-%d %H:%M:%S"), + ), + ("worker_id", "=", cur_user.partner_id.id), + ], + order="start_time desc, task_template_id, task_type_id", + limit=past_shift_limit, + ) ) else: - past_shifts = request.env['beesdoo.shift.shift'].sudo().search( - [('start_time', '<=', now.strftime("%Y-%m-%d %H:%M:%S")), - ('worker_id', '=', cur_user.partner_id.id)], - order="start_time desc, task_template_id, task_type_id", + past_shifts = ( + request.env["beesdoo.shift.shift"] + .sudo() + .search( + [ + ( + "start_time", + "<=", + now.strftime("%Y-%m-%d %H:%M:%S"), + ), + ("worker_id", "=", cur_user.partner_id.id), + ], + order="start_time desc, task_template_id, task_type_id", + ) ) - return { - 'past_shifts': past_shifts, - } + return {"past_shifts": past_shifts} def my_shift_worker_status(self): """ Return template variables for 'beesdoo_website_shift.my_shift_worker_status_*' template """ - cur_user = request.env['res.users'].browse(request.uid) - return { - 'status': cur_user.partner_id.cooperative_status_ids, - } + cur_user = request.env["res.users"].browse(request.uid) + return {"status": cur_user.partner_id.cooperative_status_ids} diff --git a/beesdoo_website_shift/models/res_config.py b/beesdoo_website_shift/models/res_config.py index dbc8382..c11dd93 100644 --- a/beesdoo_website_shift/models/res_config.py +++ b/beesdoo_website_shift/models/res_config.py @@ -2,44 +2,37 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from ast import literal_eval -from odoo import fields, models, api + +from odoo import api, fields, models class WebsiteShiftConfigSettings(models.TransientModel): - _inherit = 'res.config.settings' + _inherit = "res.config.settings" # Irregular worker settings irregular_shift_limit = fields.Integer( - related='website_id.irregular_shift_limit', - readonly=False, + related="website_id.irregular_shift_limit", readonly=False ) highlight_rule_pc = fields.Integer( - related='website_id.highlight_rule_pc', - readonly=False, + related="website_id.highlight_rule_pc", readonly=False ) hide_rule = fields.Integer( - related='website_id.highlight_rule_pc', - readonly=False, + related="website_id.highlight_rule_pc", readonly=False ) irregular_enable_sign_up = fields.Boolean( - related='website_id.irregular_enable_sign_up', - readonly=False, + related="website_id.irregular_enable_sign_up", readonly=False ) irregular_past_shift_limit = fields.Integer( - related='website_id.irregular_past_shift_limit', - readonly=False, + related="website_id.irregular_past_shift_limit", readonly=False ) # Regular worker settings regular_past_shift_limit = fields.Integer( - related='website_id.regular_past_shift_limit', - readonly=False, + related="website_id.regular_past_shift_limit", readonly=False ) regular_next_shift_limit = fields.Integer( - related='website_id.regular_next_shift_limit', - readonly=False, + related="website_id.regular_next_shift_limit", readonly=False ) regular_highlight_rule = fields.Integer( - related='website_id.regular_highlight_rule', - readonly=False, + related="website_id.regular_highlight_rule", readonly=False ) diff --git a/beesdoo_website_shift/models/website.py b/beesdoo_website_shift/models/website.py index 7e2f3b6..73f083d 100644 --- a/beesdoo_website_shift/models/website.py +++ b/beesdoo_website_shift/models/website.py @@ -5,43 +5,40 @@ from odoo import fields, models class Website(models.Model): - _inherit = 'website' + _inherit = "website" # Irregular worker settings irregular_shift_limit = fields.Integer( - default=0, - help="Maximum shift that will be shown" + default=0, help="Maximum shift that will be shown" ) highlight_rule_pc = fields.Integer( default=30, help="Treshold (in %) of available space in a shift that trigger the " - "highlight of the shift" + "highlight of the shift", ) hide_rule = fields.Integer( default=20, help="Treshold ((available space)/(max space)) in percentage of " - "available space under wich the shift is hidden" + "available space under wich the shift is hidden", ) irregular_enable_sign_up = fields.Boolean( - default=True, - help="Enable shift sign up for irregular worker" + default=True, help="Enable shift sign up for irregular worker" ) irregular_past_shift_limit = fields.Integer( default=10, - help="Maximum past shift that will be shown for irregular worker" + help="Maximum past shift that will be shown for irregular worker", ) # Regular worker settings regular_past_shift_limit = fields.Integer( default=10, - help="Maximum past shift that will be shown for regular worker" + help="Maximum past shift that will be shown for regular worker", ) regular_next_shift_limit = fields.Integer( - default=13, - help="Maximun number of next shift that will be shown" + default=13, help="Maximun number of next shift that will be shown" ) regular_highlight_rule = fields.Integer( default=20, help="Treshold (in %) of available space in a shift that trigger the " - "the highlight of a shift template." + "the highlight of a shift template.", ) diff --git a/beesdoo_website_shift/readme/CONTRIBUTORS.rst b/beesdoo_website_shift/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_website_shift/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_website_theme/__manifest__.py b/beesdoo_website_theme/__manifest__.py index ae27352..b954e3c 100644 --- a/beesdoo_website_theme/__manifest__.py +++ b/beesdoo_website_theme/__manifest__.py @@ -1,23 +1,16 @@ { - 'name': 'BEES coop Website Theme', - - 'summary': """ + "name": "BEES coop Website Theme", + "summary": """ Apply BEES coop design rules. """, - 'description': """ + "description": """ """, - - 'author': 'Rémy Taymans', - 'website': "https://github.com/beescoop/Obeesdoo", - - 'license': "AGPL-3", - 'category': 'Themes', - 'version': '12.0.0.1', - 'application': True, - - 'depends': ['website'], - - 'data': [ - 'views/assets.xml', - ] + "author": "Rémy Taymans", + "website": "https://github.com/beescoop/Obeesdoo", + "license": "AGPL-3", + "category": "Themes", + "version": "12.0.0.1", + "application": True, + "depends": ["website"], + "data": ["views/assets.xml"], } diff --git a/beesdoo_website_theme/readme/CONTRIBUTORS.rst b/beesdoo_website_theme/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..7fd2962 --- /dev/null +++ b/beesdoo_website_theme/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Beescoop - Cellule IT +* Coop IT Easy SCRLfs diff --git a/beesdoo_worker_status/__manifest__.py b/beesdoo_worker_status/__manifest__.py index abcefa2..43dbac2 100644 --- a/beesdoo_worker_status/__manifest__.py +++ b/beesdoo_worker_status/__manifest__.py @@ -1,28 +1,16 @@ +# Copyright 2020 Coop IT Easy SCRL fs +# Elouan Le Bars +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { - 'name': "Beescoop Worker Status manager", - - 'summary': """ - Worker status management specific to beescoop""", - - 'description': """ - - """, - - 'author': "Thibault Francois, Elouan Le Bars, Coop It Easy", - 'website': "https://github.com/beescoop/Obeesdoo", - - 'category': 'Cooperative management', - 'version': '12.0.1.0.0', - - 'depends': [ - 'beesdoo_base', - 'beesdoo_shift', - ], - - 'data': [ - ], - 'demo': [ - "demo/cooperators.xml", - "demo/tasks.xml", - ] + "name": "Beescoop Worker Status manager", + "summary": """ + Worker status management specific to beescoop.""", + "author": "Thibault Francois, Elouan Le Bars, Coop IT Easy SCRLfs", + "website": "https://github.com/beescoop/Obeesdoo", + "category": "Cooperative management", + "version": "12.0.1.0.0", + "depends": ["beesdoo_base", "beesdoo_shift",], + "data": [], + "demo": ["demo/cooperators.xml", "demo/tasks.xml",], + "license": "AGPL-3", } diff --git a/beesdoo_worker_status/models/cooperative_status.py b/beesdoo_worker_status/models/cooperative_status.py index 6fb2b62..f4ab122 100644 --- a/beesdoo_worker_status/models/cooperative_status.py +++ b/beesdoo_worker_status/models/cooperative_status.py @@ -1,13 +1,14 @@ -from odoo import models, fields, api, _ -from odoo.addons.beesdoo_shift.models.cooperative_status import add_days_delta -from odoo.exceptions import ValidationError, UserError - -from datetime import timedelta, datetime import logging +from datetime import datetime, timedelta + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + +from odoo.addons.beesdoo_shift.models.cooperative_status import add_days_delta class CooperativeStatus(models.Model): - _inherit = 'cooperative.status' + _inherit = "cooperative.status" _period = 28 ###################################################### @@ -16,17 +17,26 @@ class CooperativeStatus(models.Model): # # ###################################################### - future_alert_date = fields.Date(compute='_compute_future_alert_date') - next_countdown_date = fields.Date(compute='_compute_next_countdown_date') + future_alert_date = fields.Date(compute="_compute_future_alert_date") + next_countdown_date = fields.Date(compute="_compute_next_countdown_date") - @api.depends('today', 'irregular_start_date', 'sr', 'holiday_start_time', - 'holiday_end_time', 'temporary_exempt_start_date', - 'temporary_exempt_end_date') + @api.depends( + "today", + "irregular_start_date", + "sr", + "holiday_start_time", + "holiday_end_time", + "temporary_exempt_start_date", + "temporary_exempt_end_date", + ) def _compute_future_alert_date(self): """Compute date before which the worker is up to date""" for rec in self: # Only for irregular worker - if rec.working_mode != 'irregular' and not rec.irregular_start_date: + if ( + rec.working_mode != "irregular" + and not rec.irregular_start_date + ): rec.future_alert_date = False # Alert start time already set elif rec.alert_start_time: @@ -35,8 +45,9 @@ class CooperativeStatus(models.Model): elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time): rec.future_alert_date = False # Exemption have not a start and end time - elif (bool(rec.temporary_exempt_start_date) - != bool(rec.temporary_exempt_end_date)): + elif bool(rec.temporary_exempt_start_date) != bool( + rec.temporary_exempt_end_date + ): rec.future_alert_date = False else: date = rec.today @@ -48,7 +59,8 @@ class CooperativeStatus(models.Model): ) # Check holidays if ( - rec.holiday_start_time and rec.holiday_end_time + rec.holiday_start_time + and rec.holiday_end_time and date >= rec.holiday_start_time and date <= rec.holiday_end_time ): @@ -70,9 +82,14 @@ class CooperativeStatus(models.Model): rec.irregular_start_date, date ) - @api.depends('today', 'irregular_start_date', 'holiday_start_time', - 'holiday_end_time', 'temporary_exempt_start_date', - 'temporary_exempt_end_date') + @api.depends( + "today", + "irregular_start_date", + "holiday_start_time", + "holiday_end_time", + "temporary_exempt_start_date", + "temporary_exempt_end_date", + ) def _compute_next_countdown_date(self): """ Compute the following countdown date. This date is the date when @@ -82,14 +99,18 @@ class CooperativeStatus(models.Model): """ for rec in self: # Only for irregular worker - if rec.working_mode != 'irregular' and not rec.irregular_start_date: + if ( + rec.working_mode != "irregular" + and not rec.irregular_start_date + ): rec.next_countdown_date = False # Holidays are not set properly elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time): rec.next_countdown_date = False # Exemption have not a start and end time - elif (bool(rec.temporary_exempt_start_date) - != bool(rec.temporary_exempt_end_date)): + elif bool(rec.temporary_exempt_start_date) != bool( + rec.temporary_exempt_end_date + ): rec.next_countdown_date = False else: date = rec.today @@ -100,7 +121,8 @@ class CooperativeStatus(models.Model): ) # Check holidays if ( - rec.holiday_start_time and rec.holiday_end_time + rec.holiday_start_time + and rec.holiday_end_time and date >= rec.holiday_start_time and date <= rec.holiday_end_time ): @@ -124,28 +146,60 @@ class CooperativeStatus(models.Model): ##################################### def _get_regular_status(self): self.ensure_one() - counter_unsubscribe = int(self.env['ir.config_parameter'].sudo().get_param('regular_counter_to_unsubscribe', -4)) - alert_delay = int(self.env['ir.config_parameter'].sudo().get_param('alert_delay', 28)) - grace_delay = int(self.env['ir.config_parameter'].sudo().get_param('default_grace_delay', 10)) + counter_unsubscribe = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("regular_counter_to_unsubscribe", -4) + ) + alert_delay = int( + self.env["ir.config_parameter"].sudo().get_param("alert_delay", 28) + ) + grace_delay = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("default_grace_delay", 10) + ) ok = self.sr >= 0 and self.sc >= 0 grace_delay = grace_delay + self.time_extension if (self.sr + self.sc) <= counter_unsubscribe or self.unsubscribed: - return 'unsubscribed' + return "unsubscribed" # Check if exempted. Exempt end date is not required. - if self.temporary_exempt_start_date and self.today >= self.temporary_exempt_start_date: - if not self.temporary_exempt_end_date or self.today <= self.temporary_exempt_end_date: - return 'exempted' + if ( + self.temporary_exempt_start_date + and self.today >= self.temporary_exempt_start_date + ): + if ( + not self.temporary_exempt_end_date + or self.today <= self.temporary_exempt_end_date + ): + return "exempted" # Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined - if not ok and self.alert_start_time and self.extension_start_time and self.today <= add_days_delta(self.extension_start_time, grace_delay): - return 'extension' - if not ok and self.alert_start_time and self.extension_start_time and self.today > add_days_delta(self.extension_start_time, grace_delay): - return 'suspended' - if not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay): - return 'suspended' + if ( + not ok + and self.alert_start_time + and self.extension_start_time + and self.today + <= add_days_delta(self.extension_start_time, grace_delay) + ): + return "extension" + if ( + not ok + and self.alert_start_time + and self.extension_start_time + and self.today + > add_days_delta(self.extension_start_time, grace_delay) + ): + return "suspended" + if ( + not ok + and self.alert_start_time + and self.today > add_days_delta(self.alert_start_time, alert_delay) + ): + return "suspended" if (self.sr < 0) or (not ok and self.alert_start_time): - return 'alert' + return "alert" if ( self.holiday_start_time @@ -154,32 +208,64 @@ class CooperativeStatus(models.Model): and self.today <= self.holiday_end_time ): - return 'holiday' + return "holiday" elif ok or (not self.alert_start_time and self.sr >= 0): - return 'ok' + return "ok" def _get_irregular_status(self): self.ensure_one() - counter_unsubscribe = int(self.env['ir.config_parameter'].sudo().get_param('irregular_counter_to_unsubscribe', -3)) - alert_delay = int(self.env['ir.config_parameter'].sudo().get_param('alert_delay', 28)) - grace_delay = int(self.env['ir.config_parameter'].sudo().get_param('default_grace_delay', 10)) + counter_unsubscribe = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("irregular_counter_to_unsubscribe", -3) + ) + alert_delay = int( + self.env["ir.config_parameter"].sudo().get_param("alert_delay", 28) + ) + grace_delay = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("default_grace_delay", 10) + ) ok = self.sr >= 0 grace_delay = grace_delay + self.time_extension if self.sr <= counter_unsubscribe or self.unsubscribed: - return 'unsubscribed' + return "unsubscribed" # Check if exempted. Exempt end date is not required. - elif self.temporary_exempt_start_date and self.today >= self.temporary_exempt_start_date: - if not self.temporary_exempt_end_date or self.today <= self.temporary_exempt_end_date: - return 'exempted' + elif ( + self.temporary_exempt_start_date + and self.today >= self.temporary_exempt_start_date + ): + if ( + not self.temporary_exempt_end_date + or self.today <= self.temporary_exempt_end_date + ): + return "exempted" # Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined - elif not ok and self.alert_start_time and self.extension_start_time and self.today <= add_days_delta(self.extension_start_time, grace_delay): - return 'extension' - elif not ok and self.alert_start_time and self.extension_start_time and self.today > add_days_delta(self.extension_start_time, grace_delay): - return 'suspended' - elif not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay): - return 'suspended' + elif ( + not ok + and self.alert_start_time + and self.extension_start_time + and self.today + <= add_days_delta(self.extension_start_time, grace_delay) + ): + return "extension" + elif ( + not ok + and self.alert_start_time + and self.extension_start_time + and self.today + > add_days_delta(self.extension_start_time, grace_delay) + ): + return "suspended" + elif ( + not ok + and self.alert_start_time + and self.today > add_days_delta(self.alert_start_time, alert_delay) + ): + return "suspended" elif (self.sr < 0) or (not ok and self.alert_start_time): - return 'alert' + return "alert" elif ( self.holiday_start_time @@ -187,29 +273,36 @@ class CooperativeStatus(models.Model): and self.today >= self.holiday_start_time and self.today <= self.holiday_end_time ): - return 'holiday' + return "holiday" elif ok or (not self.alert_start_time and self.sr >= 0): - return 'ok' + return "ok" def _state_change(self, new_state): self.ensure_one() - if new_state == 'alert': - self.write({'alert_start_time': self.today, 'extension_start_time': False, 'time_extension': 0}) - if new_state == 'ok': - data = {'extension_start_time': False, 'time_extension': 0} - data['alert_start_time'] = False + if new_state == "alert": + self.write( + { + "alert_start_time": self.today, + "extension_start_time": False, + "time_extension": 0, + } + ) + if new_state == "ok": + data = {"extension_start_time": False, "time_extension": 0} + data["alert_start_time"] = False self.write(data) - if new_state == 'unsubscribed' or new_state == 'resigning': + if new_state == "unsubscribed" or new_state == "resigning": # Remove worker from task_templates self.cooperator_id.sudo().write( - {'subscribed_shift_ids': [(5, 0, 0)]}) + {"subscribed_shift_ids": [(5, 0, 0)]} + ) # Remove worker from supercoop in task_templates - task_tpls = self.env['beesdoo.shift.template'].search( - [('super_coop_id', 'in', self.cooperator_id.user_ids.ids)] + task_tpls = self.env["beesdoo.shift.template"].search( + [("super_coop_id", "in", self.cooperator_id.user_ids.ids)] ) - task_tpls.write({'super_coop_id': False}) + task_tpls.write({"super_coop_id": False}) # Remove worker for future tasks (remove also supercoop) - self.env['beesdoo.shift.shift'].sudo().unsubscribe_from_today( + self.env["beesdoo.shift.shift"].sudo().unsubscribe_from_today( [self.cooperator_id.id], now=fields.Datetime.now() ) @@ -218,10 +311,12 @@ class CooperativeStatus(models.Model): Call when a shift state is changed use data generated by _get_counter_date_state_change """ - self.sc += data.get('sc', 0) - self.sr += data.get('sr', 0) - self.irregular_absence_counter += data.get('irregular_absence_counter', 0) - self.irregular_absence_date = data.get('irregular_absence_date', False) + self.sc += data.get("sc", 0) + self.sr += data.get("sr", 0) + self.irregular_absence_counter += data.get( + "irregular_absence_counter", 0 + ) + self.irregular_absence_date = data.get("irregular_absence_date", False) ############################################### ###### Irregular Cron implementation ########## @@ -229,15 +324,20 @@ class CooperativeStatus(models.Model): def _get_irregular_worker_domain(self, **kwargs): today = kwargs.get("today") or self.today - return ['&', - '&', - '&', - ('status', 'not in', ['unsubscribed', 'exempted']), - ('working_mode', '=', 'irregular'), - ('irregular_start_date', '!=', False), - '|', - '|', ('holiday_start_time', '=', False), ('holiday_end_time', '=', False), - '|', ('holiday_start_time', '>', today), ('holiday_end_time', '<', today), + return [ + "&", + "&", + "&", + ("status", "not in", ["unsubscribed", "exempted"]), + ("working_mode", "=", "irregular"), + ("irregular_start_date", "!=", False), + "|", + "|", + ("holiday_start_time", "=", False), + ("holiday_end_time", "=", False), + "|", + ("holiday_start_time", ">", today), + ("holiday_end_time", "<", today), ] def _change_irregular_counter(self): diff --git a/beesdoo_worker_status/models/task.py b/beesdoo_worker_status/models/task.py index 3c485a1..c3a799e 100644 --- a/beesdoo_worker_status/models/task.py +++ b/beesdoo_worker_status/models/task.py @@ -6,7 +6,7 @@ from odoo.exceptions import UserError, ValidationError class Task(models.Model): - _inherit = 'beesdoo.shift.shift' + _inherit = "beesdoo.shift.shift" ################################# # State Definition # @@ -14,12 +14,12 @@ class Task(models.Model): def _get_selection_status(self): return [ - ("open","Confirmed"), - ("done","Attended"), - ("absent_2","Absent - 2 compensations"), - ("absent_1","Absent - 1 compensation"), - ("absent_0","Absent - 0 compensation"), - ("cancel","Cancelled") + ("open", "Confirmed"), + ("done", "Attended"), + ("absent_2", "Absent - 2 compensations"), + ("absent_1", "Absent - 1 compensation"), + ("absent_0", "Absent - 0 compensation"), + ("cancel", "Cancelled"), ] def _get_color_mapping(self, state): @@ -43,7 +43,7 @@ class Task(models.Model): ############################################## def _get_counter_date_state_change(self, new_state): data = {} - if self.worker_id.working_mode == 'regular': + if self.worker_id.working_mode == "regular": if not self.replaced_id: # No replacement case status = self.worker_id.cooperative_status_ids[0] @@ -53,29 +53,31 @@ class Task(models.Model): if new_state == "done" and not self.is_regular: # Regular counter is always updated first if status.sr < 0: - data['sr'] = 1 + data["sr"] = 1 elif status.sc < 0: - data['sc'] = 1 + data["sc"] = 1 # Bonus shift case else: - data['sr'] = 1 + data["sr"] = 1 if new_state == "absent_2": - data['sr'] = -1 - data['sc'] = -1 + data["sr"] = -1 + data["sc"] = -1 if new_state == "absent_1": - data['sr'] = -1 + data["sr"] = -1 - elif self.worker_id.working_mode == 'irregular': + elif self.worker_id.working_mode == "irregular": status = self.worker_id.cooperative_status_ids[0] if new_state == "done" or new_state == "absent_0": - data['sr'] = 1 - data['irregular_absence_date'] = False - data['irregular_absence_counter'] = 1 if status.irregular_absence_counter < 0 else 0 + data["sr"] = 1 + data["irregular_absence_date"] = False + data["irregular_absence_counter"] = ( + 1 if status.irregular_absence_counter < 0 else 0 + ) if new_state == "absent_2" or new_state == "absent_1": if new_state == "absent_2": - data['sr'] = -1 - data['irregular_absence_date'] = self.start_time.date() - data['irregular_absence_counter'] = -1 + data["sr"] = -1 + data["irregular_absence_date"] = self.start_time.date() + data["irregular_absence_counter"] = -1 return data, status diff --git a/initial-data-load/01_readme.md b/initial-data-load/01_readme.md index cb08d00..3d22ca4 100644 --- a/initial-data-load/01_readme.md +++ b/initial-data-load/01_readme.md @@ -1,4 +1,4 @@ -# Put a database dump here to load it in postgresql +# Put a database dump here to load it in postgresql Us the format `01_*.sql.gz` or `01_*.sql`. Files are loaded alphabetically, it needs to be loaded after the creation of the odoo user and before we disable cron. diff --git a/install-odoo-docker.md b/install-odoo-docker.md index f36fa10..c9ee789 100644 --- a/install-odoo-docker.md +++ b/install-odoo-docker.md @@ -26,20 +26,20 @@ docker-compose up db ``` This could take a while (~20 minutes) depending on the data dump you are using. -In order to reset your database, remove the container. +In order to reset your database, remove the container. (It will have to rebuild the database the next time you start it). ```bash docker-compose rm db ``` ## 4) Run the project -If you are not using a pre-created db run +If you are not using a pre-created db run ```bash docker-compose run odoo python3 odoo-bin -d beescoop -i base -c odoo.conf ``` All the modules need to be updated in order to be recognised. -To do that run +To do that run ```bash docker-compose run -p 8096:8096 odoo python odoo.py -c odoo.conf -d beescoop -u all ``` @@ -51,9 +51,9 @@ docker-compose up I like to start the database in the background to only have the logs of the application. ```bash -docker-compose up -d db -docker-compose up odoo -``` - +docker-compose up -d db +docker-compose up odoo +``` + ## 5) Login To login you may either use your account or the admin account whose password should have been reset to admin. diff --git a/install-odoo-linux-server.md b/install-odoo-linux-server.md index 3831591..ab9a158 100644 --- a/install-odoo-linux-server.md +++ b/install-odoo-linux-server.md @@ -1,259 +1,267 @@ # Install odoo on a linux server -> by Thibault François +> by Thibault François ## Installation basique -##### 1) ajouter un utilisateur odoo - - # adduser odoo - -##### 2) installation de postgresql (DBMS) - - # apt-get install postgresql - -##### 3) install git - - # apt-get install git - -##### 4) installer pip : python package manager - - # apt-get install python-pip - -##### 5) installation des paquets devel pour compilation des bibliothèques python - - # apt-get install python-dev postgresql-server-dev-all libjpeg-dev zlib1g-dev libpng12-dev libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev - -##### 6) installation de node-less - - # apt-get install node-less - -##### 7) clone odoo - - # su odoo - $ cd /home/odoo - $ git clone https://github.com/odoo/odoo.git - -##### 8) installer bibliothèque python - - $ exit - # cd /home/odoo/odoo - # pip install -r requirements.txt - -##### 9) créer odoo user pour postgresql avec les droits de création de base de donnée - - # su postgres - $ createuser -d odoo - $ exit - -##### 10) Installer wkhtml to pdf 0.12.1 !! (pas une autre) (sur une machine 64 bit avec un ubuntu 64bit 14.04) - - # apt-get install fontconfig libfontconfig1 libxrender1 fontconfig-config - # wget http://download.gna.org/wkhtmltopdf/0.12/0.12.1/wkhtmltox-0.12.1_linux-trusty-amd64.deb - # dpkg -i wkhtmltox-0.12.1_linux-trusty-amd64.deb - # cd /usr/local/bin/ - # cp wkhtmltoimage /usr/bin/wkhtmltoimage - # cp wkhtmltopdf /usr/bin/wkhtmltopdf - -##### 11) Tester l'installation de odoo - - # su odoo - $ cd /home/odoo/odoo - $ ./odoo.py - -lancer le navigateur http://localhost:8069 la page de création de base de donnée d'odoo devrait s'ouvrir, essayé de créer une base de donnée - -ctrl + c pour tuer le processus odoo depuis la console - -## Pour aller plus loin: init.d script - - ##### 1) créer un répertoire de log - - # su odoo - $ mkdir /home/odoo/log - - ##### 2) créer fichier de config odoo - - $ cd /home/odoo/odoo - $ ./odoo.py -s -c /home/odoo/odoo.conf --stop-after-init --logfile=/home/odoo/log/odoo.log - - ##### 3) Créer le fichier init.d - - $ exit - $ vim /etc/init.d/odoo - -copier le contenu dans le fichier (gedit va aussi bien que vim) - - - #!/bin/sh - - ### BEGIN INIT INFO - # Provides: openerp-server - # Required-Start: $remote_fs $syslog - # Required-Stop: $remote_fs $syslog - # Should-Start: $network - # Should-Stop: $network - # Default-Start: 2 3 4 5 - # Default-Stop: 0 1 6 - # Short-Description: Enterprise Resource Management software - # Description: Open ERP is a complete ERP and CRM software. - ### END INIT INFO - - PATH=/bin:/sbin:/usr/bin - DAEMON=/home/odoo/odoo/odoo.py - NAME=odoo - DESC=odoo - - # Specify the user name (Default: openerp). - USER=odoo - - # Specify an alternate config file (Default: /etc/openerp-server.conf). - CONFIGFILE="/home/odoo/odoo.conf" - - # pidfile - PIDFILE=/var/run/$NAME.pid - - # Additional options that are passed to the Daemon. - DAEMON_OPTS="-c $CONFIGFILE" - - [ -x $DAEMON ] || exit 0 - [ -f $CONFIGFILE ] || exit 0 - - checkpid() { - [ -f $PIDFILE ] || return 1 - pid=`cat $PIDFILE` - [ -d /proc/$pid ] && return 0 - pid=`cat $PIDFILE` - [ -d /proc/$pid ] && return 0 - return 1 - } - - case "${1}" in - start) - echo -n "Starting ${DESC}: " - - start-stop-daemon --start --quiet --pidfile ${PIDFILE} \ - --chuid ${USER} --background --make-pidfile \ - --exec ${DAEMON} -- ${DAEMON_OPTS} - - echo "${NAME}." - ;; - - stop) - echo -n "Stopping ${DESC}: " - - start-stop-daemon --stop --quiet --pidfile ${PIDFILE} \ - --oknodo - - echo "${NAME}." - ;; - - restart|force-reload) - echo -n "Restarting ${DESC}: " - - start-stop-daemon --stop --quiet --pidfile ${PIDFILE} \ - --oknodo - - sleep 1 - - start-stop-daemon --start --quiet --pidfile ${PIDFILE} \ - --chuid ${USER} --background --make-pidfile \ - --exec ${DAEMON} -- ${DAEMON_OPTS} - - echo "${NAME}." - - echo "${NAME}." - ;; - - *) - N=/etc/init.d/${NAME} - echo "Usage: ${NAME} {start|stop|restart|force-reload}" >&2 - exit 1 - ;; - esac - - exit 0 - - ##### 4) donner les bons droits au fichier - - # chmod 755 /etc/init.d/odoo - - ##### 5) tester le script - - # /etc/init.d/odoo start - -tester à nouveau sur localhost:8069 - - ##### 6) faire en sorte que le script s'exécute au démarrage - - # update-rc.d odoo defaults - - -## Pour aller plus loin: proxy nginx - - ##### 1) installer nginx - - # apt-get install nginx - -vous pouvez tester l'installation réussie sur http://localhost - - ##### 2) configurer nginx pour odoo : editer le fichier de conf - - # vim /etc/nginx/sites-enabled/default - -supprimer le contenu et le remplacer par - - upstream odoo { - server 127.0.0.1:8069 weight=1 fail_timeout=300s; - } - - server { - # server port and name - listen 80; - server_name localhost; - - - location / { - proxy_pass http://odoo; - # force timeouts if the backend dies - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; - - # set headers - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; - - } - } - - ##### 3) tester la config et relancer nginx - - # nginx -t - # nginx -s reload - -tester http://localhost - -devrait conduire à odoo (ne pas oublier de vider le cache de son navigateur au cas ou ca ne marche pas tout de suite) - +##### 1) ajouter un utilisateur odoo + + # adduser odoo + +##### 2) installation de postgresql (DBMS) + + # apt-get install postgresql + +##### 3) install git + + # apt-get install git + +##### 4) installer pip : python package manager + + # apt-get install python-pip + +##### 5) installation des paquets devel pour compilation des bibliothèques python + + # apt-get install python-dev postgresql-server-dev-all libjpeg-dev zlib1g-dev libpng12-dev libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev + +##### 6) installation de node-less + + # apt-get install node-less + +##### 7) clone odoo + + # su odoo + $ cd /home/odoo + $ git clone https://github.com/odoo/odoo.git + +##### 8) installer bibliothèque python + + $ exit + # cd /home/odoo/odoo + # pip install -r requirements.txt + +##### 9) créer odoo user pour postgresql avec les droits de création de base de donnée + + # su postgres + $ createuser -d odoo + $ exit + +##### 10) Installer wkhtml to pdf 0.12.1 !! (pas une autre) (sur une machine 64 bit avec un ubuntu 64bit 14.04) + + # apt-get install fontconfig libfontconfig1 libxrender1 fontconfig-config + # wget http://download.gna.org/wkhtmltopdf/0.12/0.12.1/wkhtmltox-0.12.1_linux-trusty-amd64.deb + # dpkg -i wkhtmltox-0.12.1_linux-trusty-amd64.deb + # cd /usr/local/bin/ + # cp wkhtmltoimage /usr/bin/wkhtmltoimage + # cp wkhtmltopdf /usr/bin/wkhtmltopdf + +##### 11) Tester l'installation de odoo + + # su odoo + $ cd /home/odoo/odoo + $ ./odoo.py + +lancer le navigateur http://localhost:8069 la page de création de base de donnée d'odoo devrait s'ouvrir, essayé de créer une base de donnée + +ctrl + c pour tuer le processus odoo depuis la console + +## Pour aller plus loin: init.d script + + +##### 1) créer un répertoire de log + + # su odoo + $ mkdir /home/odoo/log + + +##### 2) créer fichier de config odoo + + $ cd /home/odoo/odoo + $ ./odoo.py -s -c /home/odoo/odoo.conf --stop-after-init --logfile=/home/odoo/log/odoo.log + + +##### 3) Créer le fichier init.d + + $ exit + $ vim /etc/init.d/odoo + +copier le contenu dans le fichier (gedit va aussi bien que vim) + + + #!/bin/sh + + ### BEGIN INIT INFO + # Provides: openerp-server + # Required-Start: $remote_fs $syslog + # Required-Stop: $remote_fs $syslog + # Should-Start: $network + # Should-Stop: $network + # Default-Start: 2 3 4 5 + # Default-Stop: 0 1 6 + # Short-Description: Enterprise Resource Management software + # Description: Open ERP is a complete ERP and CRM software. + ### END INIT INFO + + PATH=/bin:/sbin:/usr/bin + DAEMON=/home/odoo/odoo/odoo.py + NAME=odoo + DESC=odoo + + # Specify the user name (Default: openerp). + USER=odoo + + # Specify an alternate config file (Default: /etc/openerp-server.conf). + CONFIGFILE="/home/odoo/odoo.conf" + + # pidfile + PIDFILE=/var/run/$NAME.pid + + # Additional options that are passed to the Daemon. + DAEMON_OPTS="-c $CONFIGFILE" + + [ -x $DAEMON ] || exit 0 + [ -f $CONFIGFILE ] || exit 0 + + checkpid() { + [ -f $PIDFILE ] || return 1 + pid=`cat $PIDFILE` + [ -d /proc/$pid ] && return 0 + pid=`cat $PIDFILE` + [ -d /proc/$pid ] && return 0 + return 1 + } + + case "${1}" in + start) + echo -n "Starting ${DESC}: " + + start-stop-daemon --start --quiet --pidfile ${PIDFILE} \ + --chuid ${USER} --background --make-pidfile \ + --exec ${DAEMON} -- ${DAEMON_OPTS} + + echo "${NAME}." + ;; + + stop) + echo -n "Stopping ${DESC}: " + + start-stop-daemon --stop --quiet --pidfile ${PIDFILE} \ + --oknodo + + echo "${NAME}." + ;; + + restart|force-reload) + echo -n "Restarting ${DESC}: " + + start-stop-daemon --stop --quiet --pidfile ${PIDFILE} \ + --oknodo + + sleep 1 + + start-stop-daemon --start --quiet --pidfile ${PIDFILE} \ + --chuid ${USER} --background --make-pidfile \ + --exec ${DAEMON} -- ${DAEMON_OPTS} + + echo "${NAME}." + + echo "${NAME}." + ;; + + *) + N=/etc/init.d/${NAME} + echo "Usage: ${NAME} {start|stop|restart|force-reload}" >&2 + exit 1 + ;; + esac + + exit 0 + + +##### 4) donner les bons droits au fichier + + # chmod 755 /etc/init.d/odoo + + +##### 5) tester le script + + # /etc/init.d/odoo start + +tester à nouveau sur localhost:8069 + + +##### 6) faire en sorte que le script s'exécute au démarrage + + # update-rc.d odoo defaults + + +## Pour aller plus loin: proxy nginx + + +##### 1) installer nginx + + # apt-get install nginx + +vous pouvez tester l'installation réussie sur http://localhost + + +##### 2) configurer nginx pour odoo : editer le fichier de conf + + # vim /etc/nginx/sites-enabled/default + +supprimer le contenu et le remplacer par + + upstream odoo { + server 127.0.0.1:8069 weight=1 fail_timeout=300s; + } + + server { + # server port and name + listen 80; + server_name localhost; + + + location / { + proxy_pass http://odoo; + # force timeouts if the backend dies + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; + + # set headers + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; + + } + } + + +##### 3) tester la config et relancer nginx + + # nginx -t + # nginx -s reload + +tester http://localhost + +devrait conduire à odoo (ne pas oublier de vider le cache de son navigateur au cas ou ca ne marche pas tout de suite) + ## Sécurité -> odoo plus accessible sur le port et changer le master password - -a) editer fichier de conf de odoo - - # vim /home/odoo/odoo.conf - -changer - - admin_passwd = admin - xmlrpc_interface = - -pour - - admin_passwd = secret_password - xmlrpc_interface = 127.0.0.1 - -b) redémarrer odoo - - # /etc/init.d/odoo restart - +> odoo plus accessible sur le port et changer le master password + +a) editer fichier de conf de odoo + + # vim /home/odoo/odoo.conf + +changer + + admin_passwd = admin + xmlrpc_interface = + +pour + + admin_passwd = secret_password + xmlrpc_interface = 127.0.0.1 + +b) redémarrer odoo + + # /etc/init.d/odoo restart diff --git a/install-odoo-linux.md b/install-odoo-linux.md index 61ccc6d..bf42439 100644 --- a/install-odoo-linux.md +++ b/install-odoo-linux.md @@ -53,4 +53,3 @@ pip install --no-binary :all: psycopg2 ``` You should now be able to start a simple odoo instance with `./odoo/odoo.py` - diff --git a/macavrac_base/__init__.py b/macavrac_base/__init__.py index 9a7e03e..0650744 100644 --- a/macavrac_base/__init__.py +++ b/macavrac_base/__init__.py @@ -1 +1 @@ -from . import models \ No newline at end of file +from . import models diff --git a/macavrac_base/__manifest__.py b/macavrac_base/__manifest__.py index 05fdcc5..a89f5ec 100644 --- a/macavrac_base/__manifest__.py +++ b/macavrac_base/__manifest__.py @@ -1,23 +1,15 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': "Macavrac Base Module", - - 'summary': """ + "name": "Macavrac Base Module", + "summary": """ Module with basic customizations for the Macavrac cooperative. """, - - 'description': """ + "description": """ """, - - 'author': "Patricia Daloze", - - 'category': 'Sales', - 'version': '12.0.1.0.0', - - 'depends': ['beesdoo_shift', 'contacts'], - - 'data': [ - 'views/res_partner.xml', - ], - 'installable': True, + "author": "Patricia Daloze", + "category": "Sales", + "version": "12.0.1.0.0", + "depends": ["beesdoo_shift", "contacts"], + "data": ["views/res_partner.xml"], + "installable": True, } diff --git a/macavrac_base/models/__init__.py b/macavrac_base/models/__init__.py index 4c58886..91fed54 100644 --- a/macavrac_base/models/__init__.py +++ b/macavrac_base/models/__init__.py @@ -1 +1 @@ -from . import res_partner \ No newline at end of file +from . import res_partner diff --git a/macavrac_base/models/res_partner.py b/macavrac_base/models/res_partner.py index 0c5e4e2..998d971 100644 --- a/macavrac_base/models/res_partner.py +++ b/macavrac_base/models/res_partner.py @@ -1,49 +1,81 @@ -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError + class Partner(models.Model): - _inherit = 'res.partner' + _inherit = "res.partner" - date_stamp = fields.Date(string="Timestamp", help="Date de remplissage du formulaire") + date_stamp = fields.Date( + string="Timestamp", help="Date de remplissage du formulaire" + ) birthdate = fields.Date(string="Date d'anniversaire") payment_date = fields.Date(string="Date de paiement") certificate_sent_date = fields.Date(string="Certificat envoyé le") - fiscal_certificate_sent_date = fields.Date(string="Attestation fiscale envoyée le") + fiscal_certificate_sent_date = fields.Date( + string="Attestation fiscale envoyée le" + ) coop_number = fields.Integer(string="Coop N°") share_qty = fields.Integer(string="Nombre de part") - share_amount = fields.Float(string="Montant", compute="_compute_share_amount") + share_amount = fields.Float( + string="Montant", compute="_compute_share_amount" + ) - gender = fields.Selection([('female','Féminin'),('male','Masculin'),('other','Autre')], string="Genre") - cooperator_type = fields.Selection([('share_a', 'Part A'), ('share_b', 'Part B'), ('share_c', 'Part C'), ('share_d', 'Part D')], string="Type de Part") - state_request = fields.Selection([('ok',"En ordre"),('waiting_payment','En attente de paiement'), - ('certificate_to_send', 'Certificat à envoyer'), ('resigning', 'Parts revendues')]) #TODO should we use the cooperative.status model instead? + gender = fields.Selection( + [("female", "Féminin"), ("male", "Masculin"), ("other", "Autre")], + string="Genre", + ) + cooperator_type = fields.Selection( + [ + ("share_a", "Part A"), + ("share_b", "Part B"), + ("share_c", "Part C"), + ("share_d", "Part D"), + ], + string="Type de Part", + ) + state_request = fields.Selection( + [ + ("ok", "En ordre"), + ("waiting_payment", "En attente de paiement"), + ("certificate_to_send", "Certificat à envoyer"), + ("resigning", "Parts revendues"), + ] + ) # TODO should we use the cooperative.status model instead? - national_register_number = fields.Char(string="Numéro de registre national") #TODO add constraint / check consistancy + national_register_number = fields.Char( + string="Numéro de registre national" + ) # TODO add constraint / check consistancy share_numbers = fields.Char(string="Numéro de parts") payment_details = fields.Char(string="Détail de paiement") - iban = fields.Char(string="IBAN") #TODO remove. Temp for import purpose. + iban = fields.Char(string="IBAN") # TODO remove. Temp for import purpose. comment_request = fields.Char(string="Commentaire") email_sent = fields.Boolean(string="Email envoyé") - is_worker = fields.Boolean(compute="_compute_is_worker", search="_search_is_worker", string="is Worker", readonly=True, related="") - + is_worker = fields.Boolean( + compute="_compute_is_worker", + search="_search_is_worker", + string="is Worker", + readonly=True, + related="", + ) - @api.depends('share_qty') + @api.depends("share_qty") def _compute_share_amount(self): for rec in self: - rec.share_amount = rec.share_qty * 25.0 #TODO add ir.config_parameter to make this amount editable + rec.share_amount = ( + rec.share_qty * 25.0 + ) # TODO add ir.config_parameter to make this amount editable - - @api.depends('cooperator_type') + @api.depends("cooperator_type") def _compute_is_worker(self): for rec in self: - rec.is_worker = rec.cooperator_type == 'share_b' + rec.is_worker = rec.cooperator_type == "share_b" def _search_is_worker(self, operator, value): - if (operator == '=' and value) or (operator == '!=' and not value): - return [('cooperator_type', '=', 'share_b')] + if (operator == "=" and value) or (operator == "!=" and not value): + return [("cooperator_type", "=", "share_b")] else: - return [('cooperator_type', '!=', 'share_b')] + return [("cooperator_type", "!=", "share_b")] diff --git a/purchase_order_generator/models/product_template.py b/purchase_order_generator/models/product_template.py index 5cd0545..86a49ba 100644 --- a/purchase_order_generator/models/product_template.py +++ b/purchase_order_generator/models/product_template.py @@ -3,7 +3,7 @@ # Vincent Van Rossem # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import models, fields, api +from odoo import api, fields, models class ProductTemplate(models.Model): diff --git a/purchase_order_generator/models/purchase_order.py b/purchase_order_generator/models/purchase_order.py index b17a488..02d626a 100644 --- a/purchase_order_generator/models/purchase_order.py +++ b/purchase_order_generator/models/purchase_order.py @@ -2,7 +2,7 @@ # Robin Keunen # Vincent Van Rossem # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import models, fields, api, SUPERUSER_ID +from odoo import SUPERUSER_ID, api, fields, models class PurchaseOrder(models.Model): diff --git a/purchase_order_generator/models/purchase_order_generator.py b/purchase_order_generator/models/purchase_order_generator.py index 7c092c8..87c7825 100644 --- a/purchase_order_generator/models/purchase_order_generator.py +++ b/purchase_order_generator/models/purchase_order_generator.py @@ -3,7 +3,7 @@ # Vincent Van Rossem # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -20,8 +20,7 @@ class PurchaseOrderGenerator(models.Model): "converted into a purchase order.", ) date_planned = fields.Datetime( - string="Date Planned", - default=fields.Datetime.now, + string="Date Planned", default=fields.Datetime.now ) supplier_id = fields.Many2one( comodel_name="res.partner", diff --git a/purchase_order_generator/models/purchase_order_generator_line.py b/purchase_order_generator/models/purchase_order_generator_line.py index 710b7ba..c0bc044 100644 --- a/purchase_order_generator/models/purchase_order_generator_line.py +++ b/purchase_order_generator/models/purchase_order_generator_line.py @@ -4,7 +4,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). import logging -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError _logger = logging.getLogger(__name__) @@ -102,7 +102,7 @@ class PurchaseOrderGeneratorLine(models.Model): if cpol.supplierinfo_id and cpol.supplierinfo_id.product_code: product_code = cpol.supplierinfo_id.product_code product_name = cpol.product_template_id.name - cpol_name = "[%s] %s" % (product_code, product_name) + cpol_name = "[{}] {}".format(product_code, product_name) else: cpol_name = cpol.product_template_id.name cpol.name = cpol_name diff --git a/purchase_order_generator/tests/test_pog.py b/purchase_order_generator/tests/test_pog.py index 4a5f9d4..644ae3c 100644 --- a/purchase_order_generator/tests/test_pog.py +++ b/purchase_order_generator/tests/test_pog.py @@ -2,7 +2,7 @@ # @author: Robin Keunen # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo.tests.common import TransactionCase, Form +from odoo.tests.common import Form, TransactionCase class TestCPO(TransactionCase): diff --git a/website_portal_restrict_modification/controllers/main.py b/website_portal_restrict_modification/controllers/main.py index d1d0c34..aa24e31 100644 --- a/website_portal_restrict_modification/controllers/main.py +++ b/website_portal_restrict_modification/controllers/main.py @@ -29,6 +29,8 @@ class CustomerPortalRestrictModification(CustomerPortal): and any("unknown field" in s.lower() for s in error_message) ): error.pop("common") - error_message = [s for s in error_message if "unknown field" not in s.lower()] + error_message = [ + s for s in error_message if "unknown field" not in s.lower() + ] return error, error_message