diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/lunch/report | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/lunch/report')
| -rw-r--r-- | addons/lunch/report/__init__.py | 5 | ||||
| -rw-r--r-- | addons/lunch/report/lunch_cashmove_report.py | 50 | ||||
| -rw-r--r-- | addons/lunch/report/lunch_cashmove_report_views.xml | 155 | ||||
| -rw-r--r-- | addons/lunch/report/lunch_product_report.py | 111 |
4 files changed, 321 insertions, 0 deletions
diff --git a/addons/lunch/report/__init__.py b/addons/lunch/report/__init__.py new file mode 100644 index 00000000..2fc4ee84 --- /dev/null +++ b/addons/lunch/report/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import lunch_cashmove_report +from . import lunch_product_report diff --git a/addons/lunch/report/lunch_cashmove_report.py b/addons/lunch/report/lunch_cashmove_report.py new file mode 100644 index 00000000..16339369 --- /dev/null +++ b/addons/lunch/report/lunch_cashmove_report.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, tools, _ + + +class CashmoveReport(models.Model): + _name = "lunch.cashmove.report" + _description = 'Cashmoves report' + _auto = False + _order = "date desc" + + id = fields.Integer('ID') + amount = fields.Float('Amount') + date = fields.Date('Date') + currency_id = fields.Many2one('res.currency', string='Currency') + user_id = fields.Many2one('res.users', string='User') + description = fields.Text('Description') + + def name_get(self): + return [(cashmove.id, '%s %s' % (_('Lunch Cashmove'), '#%d' % cashmove.id)) for cashmove in self] + + def init(self): + tools.drop_view_if_exists(self._cr, self._table) + + self._cr.execute(""" + CREATE or REPLACE view %s as ( + SELECT + lc.id as id, + lc.amount as amount, + lc.date as date, + lc.currency_id as currency_id, + lc.user_id as user_id, + lc.description as description + FROM lunch_cashmove lc + UNION ALL + SELECT + -lol.id as id, + -lol.price as amount, + lol.date as date, + lol.currency_id as currency_id, + lol.user_id as user_id, + format('Order: %%s x %%s %%s', lol.quantity::text, lp.name, lol.display_toppings) as description + FROM lunch_order lol + JOIN lunch_product lp ON lp.id = lol.product_id + WHERE + lol.state in ('ordered', 'confirmed') + AND lol.active = True + ); + """ % self._table) diff --git a/addons/lunch/report/lunch_cashmove_report_views.xml b/addons/lunch/report/lunch_cashmove_report_views.xml new file mode 100644 index 00000000..58e8b085 --- /dev/null +++ b/addons/lunch/report/lunch_cashmove_report_views.xml @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <record id="lunch_cashmove_report_view_search" model="ir.ui.view"> + <field name='name'>lunch.cashmove.report.search</field> + <field name='model'>lunch.cashmove.report</field> + <field name='arch' type='xml'> + <search string="lunch employee payment"> + <field name="description"/> + <field name="user_id"/> + <filter name='is_payment' string="Payment" domain="[('amount', '>', 0)]"/> + <separator/> + <filter name='is_mine_group' string="My Account grouped" domain="[('user_id','=',uid)]" context="{'group_by':'user_id'}"/> + <filter name="group_by_user" string="By User" context="{'group_by':'user_id'}"/> + </search> + </field> + </record> + + <record id="lunch_cashmove_report_view_search_2" model="ir.ui.view"> + <field name='name'>lunch.cashmove.report.search</field> + <field name='model'>lunch.cashmove.report</field> + <field name='arch' type='xml'> + <search string="lunch cashmove"> + <field name="description"/> + <field name="user_id"/> + <group expand="0" string="Group By"> + <filter name='group_by_user' string="By Employee" context="{'group_by':'user_id'}"/> + </group> + </search> + </field> + </record> + + <record id="lunch_cashmove_report_view_tree" model="ir.ui.view"> + <field name="name">lunch.cashmove.report.tree</field> + <field name="model">lunch.cashmove.report</field> + <field name="arch" type="xml"> + <tree string="cashmove tree"> + <field name="currency_id" invisible="1"/> + <field name="date"/> + <field name="user_id"/> + <field name="description"/> + <field name="amount" sum="Total" widget="monetary"/> + </tree> + </field> + </record> + + <record id="lunch_cashmove_report_view_tree_2" model="ir.ui.view"> + <field name="name">lunch.cashmove.report.tree</field> + <field name="model">lunch.cashmove.report</field> + <field name="arch" type="xml"> + <tree string="cashmove tree" create='false'> + <field name="currency_id" invisible="1"/> + <field name="date"/> + <field name="description"/> + <field name="amount" sum="Total" widget="monetary"/> + </tree> + </field> + </record> + + <record id="lunch_cashmove_report_view_form" model="ir.ui.view"> + <field name="name">lunch.cashmove.report.form</field> + <field name="model">lunch.cashmove.report</field> + <field name="arch" type="xml"> + <form string="cashmove form"> + <sheet> + <group> + <field name="currency_id" invisible="1"/> + <field name="user_id" required="1"/> + <field name="date"/> + <field name="amount" widget="monetary"/> + </group> + <label for='description'/> + <field name="description"/> + </sheet> + </form> + </field> + </record> + + <record id="view_lunch_cashmove_report_kanban" model="ir.ui.view"> + <field name="name">lunch.cashmove.report.kanban</field> + <field name="model">lunch.cashmove.report</field> + <field name="arch" type="xml"> + <kanban class="o_kanban_mobile"> + <field name="date"/> + <field name="user_id"/> + <field name="description"/> + <field name="amount"/> + <field name="currency_id" invisible="1"/> + <templates> + <t t-name="kanban-box"> + <div t-attf-class="oe_kanban_global_click"> + <div class="row mb4"> + <div class="col-8"> + <span> + <strong class="o_kanban_record_title"><t t-esc="record.description.value"/></strong> + </span> + </div> + <div class="col-4 text-right"> + <span class="badge badge-pill"> + <strong><i class="fa fa-money" role="img" aria-label="Amount" title="Amount"/> <field name="amount" widget="monetary"/></strong> + </span> + </div> + </div> + <div class="row"> + <div class="col-6"> + <i class="fa fa-clock-o" role="img" aria-label="Date" title="Date"/> + <t t-esc="record.date.value"/> + </div> + <div class="col-6"> + <div class="float-right"> + <field name="user_id" widget="many2one_avatar_user"/> + </div> + </div> + </div> + </div> + </t> + </templates> + </kanban> + </field> + </record> + + <record id="lunch_cashmove_report_action_account" model="ir.actions.act_window"> + <field name="name">My Account</field> + <field name="res_model">lunch.cashmove.report</field> + <field name="view_mode">tree</field> + <field name="search_view_id" ref="lunch_cashmove_report_view_search"/> + <field name="domain">[('user_id','=',uid)]</field> + <field name="view_id" ref="lunch_cashmove_report_view_tree_2"/> + <field name="help" type="html"> + <p class="o_view_nocontent_empty_folder"> + No cash move yet + </p><p> + Here you can see your cash moves.<br/>A cash move can either be an expense or a payment. + An expense is automatically created when an order is received while a payment is a reimbursement to the company encoded by the manager. + </p> + </field> + </record> + + <record id="lunch_cashmove_report_action_control_accounts" model="ir.actions.act_window"> + <field name="name">Control Accounts</field> + <field name="res_model">lunch.cashmove.report</field> + <field name="view_mode">tree,kanban,form</field> + <field name="search_view_id" ref="lunch_cashmove_report_view_search_2"/> + <field name="context">{"search_default_group_by_user":1}</field> + <field name="view_id" ref="lunch_cashmove_report_view_tree"/> + <field name="help" type="html"> + <p class="o_view_nocontent_smiling_face"> + Create a new payment + </p><p> + A cashmove can either be an expense or a payment.<br/> + An expense is automatically created at the order receipt.<br/> + A payment represents the employee reimbursement to the company. + </p> + </field> + </record> +</odoo> diff --git a/addons/lunch/report/lunch_product_report.py b/addons/lunch/report/lunch_product_report.py new file mode 100644 index 00000000..4fd2a52f --- /dev/null +++ b/addons/lunch/report/lunch_product_report.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, tools +from odoo.osv import expression + + +class LunchProductReport(models.Model): + _name = "lunch.product.report" + _description = 'Product report' + _auto = False + _order = 'is_favorite desc, is_new desc, last_order_date asc, product_id asc' + + id = fields.Integer('ID') + product_id = fields.Many2one('lunch.product', 'Product') + name = fields.Char('Product Name', related='product_id.name') + category_id = fields.Many2one('lunch.product.category', 'Product Category') + description = fields.Text('Description', related='product_id.description') + price = fields.Float('Price') + supplier_id = fields.Many2one('lunch.supplier', 'Vendor') + company_id = fields.Many2one('res.company') + currency_id = fields.Many2one('res.currency', related='company_id.currency_id') + is_favorite = fields.Boolean('Favorite') + user_id = fields.Many2one('res.users') + is_new = fields.Boolean('New') + active = fields.Boolean('Active') + last_order_date = fields.Date('Last Order Date') + image_128 = fields.Image(compute="_compute_image_128") + + # This field is used only for searching + is_available_at = fields.Many2one('lunch.location', 'Product Availability', compute='_compute_is_available_at', search='_search_is_available_at') + + def _compute_image_128(self): + for product_r in self: + product = product_r.product_id + category = product_r.sudo().category_id + if product.image_128: + product_r.image_128 = product.image_128 + elif category.image_128: + product_r.image_128 = category.image_128 + else: + product_r.image_128 = False + + def compute_concurrency_field(self): + """Image caching is based on the `__last_update` field (=self.CONCURRENCY_CHECK_FIELD) + But the image is never cached by the browser because the value fallbacks to + `now` when access logging is disabled. This override sets a "real" value based on the + product or category last update. + """ + for report in self: + product_last_update = report.product_id[self.CONCURRENCY_CHECK_FIELD] + category_last_update = report.category_id[self.CONCURRENCY_CHECK_FIELD] + report[self.CONCURRENCY_CHECK_FIELD] = max(product_last_update, category_last_update) + + def _compute_is_available_at(self): + """ + Is available_at is always false when browsing it + this field is there only to search (see _search_is_available_at) + """ + for product in self: + product.is_available_at = False + + def _search_is_available_at(self, operator, value): + supported_operators = ['in', 'not in', '=', '!='] + + if not operator in supported_operators: + return expression.TRUE_DOMAIN + + if isinstance(value, int): + value = [value] + + if operator in expression.NEGATIVE_TERM_OPERATORS: + return expression.AND([[('supplier_id.available_location_ids', 'not in', value)], [('supplier_id.available_location_ids', '!=', False)]]) + + return expression.OR([[('supplier_id.available_location_ids', 'in', value)], [('supplier_id.available_location_ids', '=', False)]]) + + def write(self, values): + if 'is_favorite' in values: + if values['is_favorite']: + commands = [(4, product_id) for product_id in self.mapped('product_id').ids] + else: + commands = [(3, product_id) for product_id in self.mapped('product_id').ids] + self.env.user.write({ + 'favorite_lunch_product_ids': commands, + }) + + def init(self): + tools.drop_view_if_exists(self._cr, self._table) + + self._cr.execute(""" + CREATE or REPLACE view %s AS ( + SELECT + row_number() over (ORDER BY users.id,product.id) AS id, + product.id AS product_id, + product.category_id, + product.price, + product.supplier_id, + product.company_id, + product.active, + users.id AS user_id, + fav.user_id IS NOT NULL AS is_favorite, + product.new_until >= current_date AS is_new, + orders.last_order_date + FROM lunch_product product + CROSS JOIN res_users users + INNER JOIN res_groups_users_rel groups ON groups.uid = users.id -- only generate for internal users + LEFT JOIN LATERAL (select max(date) AS last_order_date FROM lunch_order where user_id=users.id and product_id=product.id) AS orders ON TRUE + LEFT JOIN LATERAL (select user_id FROM lunch_product_favorite_user_rel where user_id=users.id and product_id=product.id) AS fav ON TRUE + WHERE users.active AND product.active AND groups.gid = %%s --only take into account active products and users + ); + """ % self._table, (self.env.ref('base.group_user').id,)) |
