summaryrefslogtreecommitdiff
path: root/addons/lunch/report
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/report
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/lunch/report')
-rw-r--r--addons/lunch/report/__init__.py5
-rw-r--r--addons/lunch/report/lunch_cashmove_report.py50
-rw-r--r--addons/lunch/report/lunch_cashmove_report_views.xml155
-rw-r--r--addons/lunch/report/lunch_product_report.py111
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,))