summaryrefslogtreecommitdiff
path: root/addons/lunch/models/lunch_supplier.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/lunch/models/lunch_supplier.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/lunch/models/lunch_supplier.py')
-rw-r--r--addons/lunch/models/lunch_supplier.py187
1 files changed, 187 insertions, 0 deletions
diff --git a/addons/lunch/models/lunch_supplier.py b/addons/lunch/models/lunch_supplier.py
new file mode 100644
index 00000000..2514f03f
--- /dev/null
+++ b/addons/lunch/models/lunch_supplier.py
@@ -0,0 +1,187 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import math
+import pytz
+
+from datetime import datetime, time
+
+from odoo import api, fields, models
+from odoo.osv import expression
+from odoo.tools import float_round
+
+from odoo.addons.base.models.res_partner import _tz_get
+
+
+WEEKDAY_TO_NAME = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
+
+def float_to_time(hours, moment='am', tz=None):
+ """ Convert a number of hours into a time object. """
+ if hours == 12.0 and moment == 'pm':
+ return time.max
+ fractional, integral = math.modf(hours)
+ if moment == 'pm':
+ integral += 12
+ res = time(int(integral), int(float_round(60 * fractional, precision_digits=0)), 0)
+ if tz:
+ res = res.replace(tzinfo=pytz.timezone(tz))
+ return res
+
+def time_to_float(t):
+ return float_round(t.hour + t.minute/60 + t.second/3600, precision_digits=2)
+
+class LunchSupplier(models.Model):
+ _name = 'lunch.supplier'
+ _description = 'Lunch Supplier'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+
+ partner_id = fields.Many2one('res.partner', string='Vendor', required=True)
+
+ name = fields.Char('Name', related='partner_id.name', readonly=False)
+
+ email = fields.Char(related='partner_id.email', readonly=False)
+ email_formatted = fields.Char(related='partner_id.email_formatted', readonly=True)
+ phone = fields.Char(related='partner_id.phone', readonly=False)
+ street = fields.Char(related='partner_id.street', readonly=False)
+ street2 = fields.Char(related='partner_id.street2', readonly=False)
+ zip_code = fields.Char(related='partner_id.zip', readonly=False)
+ city = fields.Char(related='partner_id.city', readonly=False)
+ state_id = fields.Many2one("res.country.state", related='partner_id.state_id', readonly=False)
+ country_id = fields.Many2one('res.country', related='partner_id.country_id', readonly=False)
+ company_id = fields.Many2one('res.company', related='partner_id.company_id', readonly=False, store=True)
+
+ responsible_id = fields.Many2one('res.users', string="Responsible", domain=lambda self: [('groups_id', 'in', self.env.ref('lunch.group_lunch_manager').id)],
+ default=lambda self: self.env.user,
+ help="The responsible is the person that will order lunch for everyone. It will be used as the 'from' when sending the automatic email.")
+
+ send_by = fields.Selection([
+ ('phone', 'Phone'),
+ ('mail', 'Email'),
+ ], 'Send Order By', default='phone')
+ automatic_email_time = fields.Float('Order Time', default=12.0, required=True)
+
+ recurrency_monday = fields.Boolean('Monday', default=True)
+ recurrency_tuesday = fields.Boolean('Tuesday', default=True)
+ recurrency_wednesday = fields.Boolean('Wednesday', default=True)
+ recurrency_thursday = fields.Boolean('Thursday', default=True)
+ recurrency_friday = fields.Boolean('Friday', default=True)
+ recurrency_saturday = fields.Boolean('Saturday')
+ recurrency_sunday = fields.Boolean('Sunday')
+
+ recurrency_end_date = fields.Date('Until', help="This field is used in order to ")
+
+ available_location_ids = fields.Many2many('lunch.location', string='Location')
+ available_today = fields.Boolean('This is True when if the supplier is available today',
+ compute='_compute_available_today', search='_search_available_today')
+
+ tz = fields.Selection(_tz_get, string='Timezone', required=True, default=lambda self: self.env.user.tz or 'UTC')
+
+ active = fields.Boolean(default=True)
+
+ moment = fields.Selection([
+ ('am', 'AM'),
+ ('pm', 'PM'),
+ ], default='am', required=True)
+
+ delivery = fields.Selection([
+ ('delivery', 'Delivery'),
+ ('no_delivery', 'No Delivery')
+ ], default='no_delivery')
+
+ _sql_constraints = [
+ ('automatic_email_time_range',
+ 'CHECK(automatic_email_time >= 0 AND automatic_email_time <= 12)',
+ 'Automatic Email Sending Time should be between 0 and 12'),
+ ]
+
+ def name_get(self):
+ res = []
+ for supplier in self:
+ if supplier.phone:
+ res.append((supplier.id, '%s %s' % (supplier.name, supplier.phone)))
+ else:
+ res.append((supplier.id, supplier.name))
+ return res
+
+ def toggle_active(self):
+ """ Archiving related lunch product """
+ res = super().toggle_active()
+ Product = self.env['lunch.product'].with_context(active_test=False)
+ all_products = Product.search([('supplier_id', 'in', self.ids)])
+ all_products._sync_active_from_related()
+ return res
+
+ @api.model
+ def _auto_email_send(self):
+ """
+ This method is called every 20 minutes via a cron.
+ Its job is simply to get all the orders made for each supplier and send an email
+ automatically to the supplier if the supplier is configured for it and we are ready
+ to send it (usually at 11am or so)
+ """
+ records = self.search([('send_by', '=', 'mail')])
+
+ for supplier in records:
+ send_at = datetime.combine(fields.Date.today(),
+ float_to_time(supplier.automatic_email_time, supplier.moment, supplier.tz)).astimezone(pytz.UTC).replace(tzinfo=None)
+ if supplier.available_today and fields.Datetime.now() > send_at:
+ lines = self.env['lunch.order'].search([('supplier_id', '=', supplier.id),
+ ('state', '=', 'ordered'), ('date', '=', fields.Date.today())])
+
+ if lines:
+ order = {
+ 'company_name': lines[0].company_id.name,
+ 'currency_id': lines[0].currency_id.id,
+ 'supplier_id': supplier.partner_id.id,
+ 'supplier_name': supplier.name,
+ 'email_from': supplier.responsible_id.email_formatted,
+ }
+
+ _lines = [{
+ 'product': line.product_id.name,
+ 'note': line.note,
+ 'quantity': line.quantity,
+ 'price': line.price,
+ 'toppings': line.display_toppings,
+ 'username': line.user_id.name,
+ } for line in lines]
+
+ order['amount_total'] = sum(line.price for line in lines)
+
+ self.env.ref('lunch.lunch_order_mail_supplier').with_context(order=order, lines=_lines).send_mail(supplier.id)
+
+ lines.action_confirm()
+
+ @api.depends('recurrency_end_date', 'recurrency_monday', 'recurrency_tuesday',
+ 'recurrency_wednesday', 'recurrency_thursday', 'recurrency_friday',
+ 'recurrency_saturday', 'recurrency_sunday')
+ def _compute_available_today(self):
+ now = fields.Datetime.now().replace(tzinfo=pytz.UTC)
+
+ for supplier in self:
+ now = now.astimezone(pytz.timezone(supplier.tz))
+
+ if supplier.recurrency_end_date and now.date() >= supplier.recurrency_end_date:
+ supplier.available_today = False
+ else:
+ fieldname = 'recurrency_%s' % (WEEKDAY_TO_NAME[now.weekday()])
+ supplier.available_today = supplier[fieldname]
+
+ def _search_available_today(self, operator, value):
+ if (not operator in ['=', '!=']) or (not value in [True, False]):
+ return []
+
+ searching_for_true = (operator == '=' and value) or (operator == '!=' and not value)
+
+ now = fields.Datetime.now().replace(tzinfo=pytz.UTC).astimezone(pytz.timezone(self.env.user.tz or 'UTC'))
+ fieldname = 'recurrency_%s' % (WEEKDAY_TO_NAME[now.weekday()])
+
+ recurrency_domain = expression.OR([
+ [('recurrency_end_date', '=', False)],
+ [('recurrency_end_date', '>' if searching_for_true else '<', now)]
+ ])
+
+ return expression.AND([
+ recurrency_domain,
+ [(fieldname, operator, value)]
+ ])