diff --git a/beesdoo_base/__init__.py b/beesdoo_base/__init__.py
index eca5f1d..7a60277 100644
--- a/beesdoo_base/__init__.py
+++ b/beesdoo_base/__init__.py
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
import models
import wizard
-import controllers
\ No newline at end of file
+import controllers
diff --git a/beesdoo_base/__openerp__.py b/beesdoo_base/__openerp__.py
index 8753643..84ee85d 100644
--- a/beesdoo_base/__openerp__.py
+++ b/beesdoo_base/__openerp__.py
@@ -1,29 +1,30 @@
# -*- coding: utf-8 -*-
{
- 'name': "Beescoop Base Module",
-
- 'summary': """
+ "name": "Beescoop Base Module",
+ "summary": """
Module that customize the base module and contains some python tools
""",
-
- 'description': """
+ "description": """
""",
-
- 'author': "Beescoop - Cellule IT",
- 'website': "https://github.com/beescoop/Obeesdoo",
-
- 'category': 'Project Management',
- 'version': '9.0.1.0.1',
-
- 'depends': ['point_of_sale', 'purchase', 'report', 'portal', 'partner_firstname'],
-
- 'data': [
- 'security/groups.xml',
- 'security/ir.model.access.csv',
- 'views/partner.xml',
- 'wizard/views/member_card.xml',
- 'wizard/views/partner.xml',
- 'data/default_contact.xml',
- 'report/beescard.xml',
+ "author": "Beescoop - Cellule IT",
+ "website": "https://github.com/beescoop/Obeesdoo",
+ "category": "Project Management",
+ "version": "9.0.1.0.1",
+ "depends": [
+ "point_of_sale",
+ "purchase",
+ "report",
+ "portal",
+ "partner_firstname",
+ ],
+ "data": [
+ "security/groups.xml",
+ "security/ir.model.access.csv",
+ "data/cron.xml",
+ "views/partner.xml",
+ "wizard/views/member_card.xml",
+ "wizard/views/partner.xml",
+ "data/default_contact.xml",
+ "report/beescard.xml",
],
}
diff --git a/beesdoo_base/controllers/__init__.py b/beesdoo_base/controllers/__init__.py
index 097e4d2..4cb5de9 100644
--- a/beesdoo_base/controllers/__init__.py
+++ b/beesdoo_base/controllers/__init__.py
@@ -1 +1 @@
-import report
\ No newline at end of file
+import report
diff --git a/beesdoo_base/controllers/report.py b/beesdoo_base/controllers/report.py
index b8d441f..9200b03 100644
--- a/beesdoo_base/controllers/report.py
+++ b/beesdoo_base/controllers/report.py
@@ -2,7 +2,10 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.addons.web.http import Controller, route, request
-from openerp.addons.web.controllers.main import _serialize_exception, content_disposition
+from openerp.addons.web.controllers.main import (
+ _serialize_exception,
+ content_disposition,
+)
from openerp.tools import html_escape
import json
@@ -17,8 +20,7 @@ from openerp.tools.safe_eval import safe_eval
class ReportCustom(ReportController):
-
- @route(['/report/download'], type='http', auth="user")
+ @route(["/report/download"], type="http", auth="user")
def report_download(self, data, token):
"""This function is used by 'qwebactionmanager.js' in order to trigger the download of
a pdf/controller report.
@@ -30,44 +32,54 @@ class ReportCustom(ReportController):
requestcontent = json.loads(data)
url, type = requestcontent[0], requestcontent[1]
try:
- if type == 'qweb-pdf':
- reportname = url.split('/report/pdf/')[1].split('?')[0]
+ if type == "qweb-pdf":
+ reportname = url.split("/report/pdf/")[1].split("?")[0]
docids = None
- if '/' in reportname:
- reportname, docids = reportname.split('/')
+ if "/" in reportname:
+ reportname, docids = reportname.split("/")
if docids:
# Generic report:
- response = self.report_routes(reportname, docids=docids, converter='pdf')
+ response = self.report_routes(
+ reportname, docids=docids, converter="pdf"
+ )
else:
# Particular report:
- data = url_decode(url.split('?')[1]).items() # decoding the args represented in JSON
- response = self.report_routes(reportname, converter='pdf', **dict(data))
+ data = url_decode(
+ url.split("?")[1]
+ ).items() # decoding the args represented in JSON
+ response = self.report_routes(
+ reportname, converter="pdf", **dict(data)
+ )
cr, uid = request.cr, request.uid
- report = request.registry['report']._get_report_from_name(cr, uid, reportname)
+ report = request.registry["report"]._get_report_from_name(
+ cr, uid, reportname
+ )
filename = "%s.%s" % (report.name, "pdf")
if docids:
ids = [int(x) for x in docids.split(",")]
obj = request.env[report.model].browse(ids)
if report.attachment and not len(obj) > 1:
- filename = safe_eval(report.attachment, {'object': obj, 'time': time})
- response.headers.add('Content-Disposition', content_disposition(filename))
- response.set_cookie('fileToken', token)
+ filename = safe_eval(
+ report.attachment, {"object": obj, "time": time}
+ )
+ response.headers.add(
+ "Content-Disposition", content_disposition(filename)
+ )
+ response.set_cookie("fileToken", token)
return response
- elif type =='controller':
+ elif type == "controller":
reqheaders = Headers(request.httprequest.headers)
- response = Client(request.httprequest.app, BaseResponse).get(url, headers=reqheaders, follow_redirects=True)
- response.set_cookie('fileToken', token)
+ response = Client(request.httprequest.app, BaseResponse).get(
+ url, headers=reqheaders, follow_redirects=True
+ )
+ response.set_cookie("fileToken", token)
return response
else:
return
- except Exception, e:
+ except Exception as e:
se = _serialize_exception(e)
- error = {
- 'code': 200,
- 'message': "Odoo Server Error",
- 'data': se
- }
+ error = {"code": 200, "message": "Odoo Server Error", "data": se}
return request.make_response(html_escape(json.dumps(error)))
diff --git a/beesdoo_base/data/cron.xml b/beesdoo_base/data/cron.xml
new file mode 100644
index 0000000..21a895c
--- /dev/null
+++ b/beesdoo_base/data/cron.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Procurement: cleanup procurement orders blocking the procurement rules
+
+
+ 1
+ days
+ -1
+
+ procurement.order
+ cron_cleanup_procurement_order
+ ()
+
+
+
diff --git a/beesdoo_base/models/__init__.py b/beesdoo_base/models/__init__.py
index f95b336..acd14bf 100644
--- a/beesdoo_base/models/__init__.py
+++ b/beesdoo_base/models/__init__.py
@@ -1 +1,3 @@
-import partner, membercard
\ No newline at end of file
+from . import partner
+from . import membercard
+from . import procurement
diff --git a/beesdoo_base/models/membercard.py b/beesdoo_base/models/membercard.py
index 0bbd5ae..97ef45a 100644
--- a/beesdoo_base/models/membercard.py
+++ b/beesdoo_base/models/membercard.py
@@ -2,23 +2,33 @@
from openerp import models, fields, api
import uuid
-class MemberCard(models.Model):
+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"
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 7c048bf..c8ed4f1 100644
--- a/beesdoo_base/models/partner.py
+++ b/beesdoo_base/models/partner.py
@@ -2,28 +2,55 @@
from openerp import models, fields, api, _
from openerp.exceptions import ValidationError
-class Partner(models.Model):
- _inherit = 'res.partner'
+class Partner(models.Model):
- 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')
- country_id = fields.Many2one(required=True, default=lambda self: self.env.ref('base.be'))
+ _inherit = "res.partner"
- member_card_to_be_printed = fields.Boolean('Print BEES card?')
- last_printed = fields.Datetime('Last printed on')
- cooperator_type = fields.Selection([('share_a', 'Share A'), ('share_b', 'Share B'), ('share_c', 'Share C')], store=True, compute=None)
+ 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")
+ country_id = fields.Many2one(
+ required=True, default=lambda self: self.env.ref("base.be")
+ )
+ member_card_to_be_printed = fields.Boolean("Print BEES card?")
+ last_printed = fields.Datetime("Last printed on")
+ cooperator_type = fields.Selection(
+ [
+ ("share_a", "Share A"),
+ ("share_b", "Share B"),
+ ("share_c", "Share C"),
+ ],
+ store=True,
+ compute=None,
+ )
@api.one
- @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):
- if self.eater == 'eater':
+ if self.eater == "eater":
self.parent_barcode = self.parent_eater_id.barcode
elif self.member_card_ids:
for c in self.member_card_ids:
@@ -31,7 +58,7 @@ class Partner(models.Model):
self.barcode = c.barcode
@api.one
- @api.constrains('child_eater_ids', 'parent_eater_id')
+ @api.constrains("child_eater_ids", "parent_eater_id")
def _check_number_of_eaters(self):
"""The owner of an A share can have a maximum of two eaters but
the owner of a B share can have a maximum of three eaters.
@@ -40,52 +67,65 @@ class Partner(models.Model):
share_type_code = self.cooperator_type
parent_share_type_code = self.parent_eater_id.cooperator_type
# Raise exception
- if share_type_code == 'share_b' or parent_share_type_code == 'share_b':
- if len(self.child_eater_ids) > 3 or len(self.parent_eater_id.child_eater_ids) > 3:
- raise ValidationError(_('You can only set three additional eaters per worker'))
+ if share_type_code == "share_b" or parent_share_type_code == "share_b":
+ if (
+ len(self.child_eater_ids) > 3
+ or len(self.parent_eater_id.child_eater_ids) > 3
+ ):
+ raise ValidationError(
+ _("You can only set three additional eaters per worker")
+ )
else:
- if len(self.child_eater_ids) > 2 or len(self.parent_eater_id.child_eater_ids) > 2:
- raise ValidationError(_('You can only set two additional eaters per worker'))
-
+ if (
+ len(self.child_eater_ids) > 2
+ or len(self.parent_eater_id.child_eater_ids) > 2
+ ):
+ raise ValidationError(
+ _("You can only set two additional eaters per worker")
+ )
@api.multi
def write(self, values):
- if values.get('parent_eater_id') and self.parent_eater_id:
- raise ValidationError(_('You try to assign a eater to a worker but this easer is alread assign to %s please remove it before') % self.parent_eater_id.name)
+ if values.get("parent_eater_id") and self.parent_eater_id:
+ raise ValidationError(
+ _(
+ "You try to assign a eater to a worker but this easer is alread assign to %s please remove it before"
+ )
+ % self.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)
@api.one
def _deactivate_active_cards(self):
- 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/models/procurement.py b/beesdoo_base/models/procurement.py
new file mode 100644
index 0000000..e21ef99
--- /dev/null
+++ b/beesdoo_base/models/procurement.py
@@ -0,0 +1,57 @@
+# Copyright 2019 Coop IT Easy SCRL fs
+# Robin Keunen
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+
+from openerp import models, fields, api
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class ProcurementOrder(models.Model):
+ _inherit = "procurement.order"
+
+ @api.model
+ def cron_cleanup_procurement_order(self):
+ running_procurement = self.env["procurement.order"].search(
+ [("state", "=", "running")]
+ )
+
+ # checks if procurement order is done
+ # -> if all moves are 'done' or 'cancel'
+ _logger.info("check procurements in running state.")
+ running_procurement.check()
+
+ # in remaining procurement, cancel those with no procurement order
+ unlinked_procurement = self.env["procurement.order"].search(
+ [("state", "=", "running"), ("purchase_line_id", "=", False)]
+ )
+ _logger.info(
+ "cancelling %s procurement unlinked from PO."
+ % len(unlinked_procurement)
+ )
+ unlinked_procurement.cancel()
+
+ # in remaining procurement, delete those from 'done' purchase order
+ procurement_linked_to_done_PO = self.env["procurement.order"].search(
+ [
+ ("state", "=", "running"),
+ ("purchase_line_id", "!=", False),
+ ("purchase_line_id.order_id.state", "=", "done"),
+ ]
+ )
+ _logger.info(
+ "set %s procurement to done (linked to done PO)"
+ % len(procurement_linked_to_done_PO)
+ )
+ procurement_linked_to_done_PO.write({"state": "done"})
+
+ # cancel procurement order from exceptions
+ exception_procurement = self.env["procurement.order"].search(
+ [("state", "=", "exception"), ("purchase_line_id", "=", False)]
+ )
+ _logger.info(
+ "cancelling %s procurement in exception"
+ % len(exception_procurement)
+ )
+ exception_procurement.cancel()
diff --git a/beesdoo_base/wizard/__init__.py b/beesdoo_base/wizard/__init__.py
index 5368e4a..f1007d6 100644
--- a/beesdoo_base/wizard/__init__.py
+++ b/beesdoo_base/wizard/__init__.py
@@ -1,2 +1 @@
import member_card, partner, portal_wizard
-
diff --git a/beesdoo_base/wizard/member_card.py b/beesdoo_base/wizard/member_card.py
index ff72910..1e06d12 100644
--- a/beesdoo_base/wizard/member_card.py
+++ b/beesdoo_base/wizard/member_card.py
@@ -1,52 +1,67 @@
# -*- coding: utf-8 -*-
from openerp import models, fields, api
+
class NewMemberCardWizard(models.TransientModel):
"""
A transient model for the creation of a new card.
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"
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"
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"
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 c04ab93..01cd071 100644
--- a/beesdoo_base/wizard/partner.py
+++ b/beesdoo_base/wizard/partner.py
@@ -1,20 +1,22 @@
# -*- coding: utf-8 -*-
from openerp import models, fields, api
+
class NewEaterWizard(models.TransientModel):
"""
A transient model for the creation of a eater related to a worker.
"""
- _name = 'eater.new.wizard'
+
+ _name = "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 1f2645b..0db0f85 100644
--- a/beesdoo_base/wizard/portal_wizard.py
+++ b/beesdoo_base/wizard/portal_wizard.py
@@ -1,26 +1,30 @@
from openerp import models, fields, api
from openerp import SUPERUSER_ID
+
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,
+ }
+ )