mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-28 00:12:01 +02:00
Initial commit: Sale packages
This commit is contained in:
commit
14e3d26998
6469 changed files with 2479670 additions and 0 deletions
|
|
@ -0,0 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import pos_details
|
||||
from . import pos_payment
|
||||
from . import pos_close_session_wizard
|
||||
from . import pos_session_check_product_wizard
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PosCloseSessionWizard(models.TransientModel):
|
||||
_name = "pos.close.session.wizard"
|
||||
_description = "Close Session Wizard"
|
||||
|
||||
amount_to_balance = fields.Float("Amount to balance")
|
||||
account_id = fields.Many2one("account.account", "Destination account")
|
||||
account_readonly = fields.Boolean("Destination account is readonly")
|
||||
message = fields.Text("Information message")
|
||||
|
||||
def close_session(self):
|
||||
session = self.env["pos.session"].browse(self.env.context["active_ids"])
|
||||
return session.action_pos_session_closing_control(
|
||||
self.account_id, self.amount_to_balance
|
||||
)
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_form_pos_close_session_wizard" model="ir.ui.view">
|
||||
<field name="name">pos.close.session.wizard.form</field>
|
||||
<field name="model">pos.close.session.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Force Close Session">
|
||||
<p><field name="message" readonly="1" /></p>
|
||||
<group>
|
||||
<field name="account_readonly" invisible="1" />
|
||||
<field name="amount_to_balance" readonly="1" />
|
||||
<field name="account_id" attrs="{'readonly': [('account_readonly', '==', True)]}"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="close_session" string="Close Session" type="object" class="btn-primary" data-hotkey="q"/>
|
||||
<button special="cancel" data-hotkey="z" string="Cancel" class="btn-secondary" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class PosDetails(models.TransientModel):
|
||||
_name = 'pos.details.wizard'
|
||||
_description = 'Point of Sale Details Report'
|
||||
|
||||
def _default_start_date(self):
|
||||
""" Find the earliest start_date of the latests sessions """
|
||||
# restrict to configs available to the user
|
||||
config_ids = self.env['pos.config'].search([]).ids
|
||||
# exclude configs has not been opened for 2 days
|
||||
self.env.cr.execute("""
|
||||
SELECT
|
||||
max(start_at) as start,
|
||||
config_id
|
||||
FROM pos_session
|
||||
WHERE config_id = ANY(%s)
|
||||
AND start_at > (NOW() - INTERVAL '2 DAYS')
|
||||
GROUP BY config_id
|
||||
""", (config_ids,))
|
||||
latest_start_dates = [res['start'] for res in self.env.cr.dictfetchall()]
|
||||
# earliest of the latest sessions
|
||||
return latest_start_dates and min(latest_start_dates) or fields.Datetime.now()
|
||||
|
||||
start_date = fields.Datetime(required=True, default=_default_start_date)
|
||||
end_date = fields.Datetime(required=True, default=fields.Datetime.now)
|
||||
pos_config_ids = fields.Many2many('pos.config', 'pos_detail_configs',
|
||||
default=lambda s: s.env['pos.config'].search([]))
|
||||
|
||||
@api.onchange('start_date')
|
||||
def _onchange_start_date(self):
|
||||
if self.start_date and self.end_date and self.end_date < self.start_date:
|
||||
self.end_date = self.start_date
|
||||
|
||||
@api.onchange('end_date')
|
||||
def _onchange_end_date(self):
|
||||
if self.end_date and self.start_date and self.end_date < self.start_date:
|
||||
self.start_date = self.end_date
|
||||
|
||||
def generate_report(self):
|
||||
data = {'date_start': self.start_date, 'date_stop': self.end_date, 'config_ids': self.pos_config_ids.ids}
|
||||
return self.env.ref('point_of_sale.sale_details_report').report_action([], data=data)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_pos_details_wizard" model="ir.ui.view">
|
||||
<field name="name">pos.details.wizard.form</field>
|
||||
<field name="model">pos.details.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Sales Details">
|
||||
<group>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pos_config_ids" mode="tree" colspan="2" nolabel="1" />
|
||||
</group>
|
||||
<footer>
|
||||
<button name="generate_report" string="Print" type="object" class="btn-primary" data-hotkey="q"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" data-hotkey="z" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools import float_is_zero
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class PosMakePayment(models.TransientModel):
|
||||
_name = 'pos.make.payment'
|
||||
_description = 'Point of Sale Make Payment Wizard'
|
||||
|
||||
def _default_config(self):
|
||||
active_id = self.env.context.get('active_id')
|
||||
if active_id:
|
||||
return self.env['pos.order'].browse(active_id).session_id.config_id
|
||||
return False
|
||||
|
||||
def _default_amount(self):
|
||||
active_id = self.env.context.get('active_id')
|
||||
if active_id:
|
||||
order = self.env['pos.order'].browse(active_id)
|
||||
amount_total = order.amount_total
|
||||
# If we refund the entire order, we refund what was paid originally, else we refund the value of the items returned
|
||||
if float_is_zero(order.refunded_order_ids.amount_total + order.amount_total, precision_rounding=order.currency_id.rounding):
|
||||
amount_total = -order.refunded_order_ids.amount_paid
|
||||
return amount_total - order.amount_paid
|
||||
return False
|
||||
|
||||
def _default_payment_method(self):
|
||||
active_id = self.env.context.get('active_id')
|
||||
if active_id:
|
||||
order_id = self.env['pos.order'].browse(active_id)
|
||||
return order_id.session_id.payment_method_ids.sorted(lambda pm: pm.is_cash_count, reverse=True)[:1]
|
||||
return False
|
||||
|
||||
config_id = fields.Many2one('pos.config', string='Point of Sale Configuration', required=True, default=_default_config)
|
||||
amount = fields.Float(digits=0, required=True, default=_default_amount)
|
||||
payment_method_id = fields.Many2one('pos.payment.method', string='Payment Method', required=True, default=_default_payment_method)
|
||||
payment_name = fields.Char(string='Payment Reference')
|
||||
payment_date = fields.Datetime(string='Payment Date', required=True, default=lambda self: fields.Datetime.now())
|
||||
|
||||
def check(self):
|
||||
"""Check the order:
|
||||
if the order is not paid: continue payment,
|
||||
if the order is paid print ticket.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
order = self.env['pos.order'].browse(self.env.context.get('active_id', False))
|
||||
if self.payment_method_id.split_transactions and not order.partner_id:
|
||||
raise UserError(_(
|
||||
"Customer is required for %s payment method.",
|
||||
self.payment_method_id.name
|
||||
))
|
||||
|
||||
currency = order.currency_id
|
||||
|
||||
init_data = self.read()[0]
|
||||
if not float_is_zero(init_data['amount'], precision_rounding=currency.rounding):
|
||||
order.add_payment({
|
||||
'pos_order_id': order.id,
|
||||
'amount': order._get_rounded_amount(init_data['amount']),
|
||||
'name': init_data['payment_name'],
|
||||
'payment_method_id': init_data['payment_method_id'][0],
|
||||
})
|
||||
|
||||
if order._is_pos_order_paid():
|
||||
order.action_pos_order_paid()
|
||||
order._create_order_picking()
|
||||
order._compute_total_cost_in_real_time()
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
return self.launch_payment()
|
||||
|
||||
def launch_payment(self):
|
||||
return {
|
||||
'name': _('Payment'),
|
||||
'view_mode': 'form',
|
||||
'res_model': 'pos.make.payment',
|
||||
'view_id': False,
|
||||
'target': 'new',
|
||||
'views': False,
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': self.env.context,
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_pos_payment" model="ir.ui.view">
|
||||
<field name="name">pos.make.payment.form</field>
|
||||
<field name="model">pos.make.payment</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Pay Order">
|
||||
<group>
|
||||
<field name="config_id" invisible="1" />
|
||||
<field name="payment_method_id" domain="[('config_ids', 'in', config_id)]"/>
|
||||
<field name="amount" />
|
||||
<field name="payment_name"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="check" string="Make Payment" type="object" class="btn-primary" data-hotkey="q"/>
|
||||
<button special="cancel" data-hotkey="z" string="Cancel" class="btn-secondary"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_pos_payment" model="ir.actions.act_window">
|
||||
<field name="name">Payment</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">pos.make.payment</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
from odoo.exceptions import AccessDenied
|
||||
from odoo.tools import convert
|
||||
|
||||
|
||||
class PosSessionCheckProductWizard(models.TransientModel):
|
||||
_name = 'pos.session.check_product_wizard'
|
||||
_description = 'Verify if there are any products for the PoS'
|
||||
|
||||
def load_demo_products(self):
|
||||
if not self.env.user.has_group("point_of_sale.group_pos_user"):
|
||||
raise AccessDenied()
|
||||
convert.convert_file(self.env.cr, 'point_of_sale', 'data/point_of_sale_onboarding.xml', None, mode='init', kind='data')
|
||||
return self.open_ui()
|
||||
|
||||
def open_ui(self):
|
||||
config = self.env['pos.config'].browse(self.env.context.get('config_id'))
|
||||
return config._action_to_open_ui()
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_pos_session_check_product_wizard" model="ir.ui.view">
|
||||
<field name="name">pos.session.check.product.wizard.form</field>
|
||||
<field name="model">pos.session.check_product_wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Check products">
|
||||
<p>
|
||||
You can add some from the Products menu, or linked any existing by flagging them as "Available in PoS".
|
||||
Or you can add demo data for testing purpose. Please mind that this is an irreversible action.
|
||||
</p>
|
||||
<footer>
|
||||
<button name="load_demo_products" string="Add demo data" type="object" class="btn-primary" data-hotkey="q"/>
|
||||
<button name="open_ui" string="Continue without Demo data" type="object" class="btn-secondary" data-hotkey="z" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Add table
Add a link
Reference in a new issue