-
151pos_order_to_sale_order/README.rst
-
1pos_order_to_sale_order/__init__.py
-
12pos_order_to_sale_order/__manifest__.py
-
7pos_order_to_sale_order/demo/res_groups.xml
-
179pos_order_to_sale_order/i18n/fr.po
-
106pos_order_to_sale_order/i18n/pos_order_to_sale_order.pot
-
2pos_order_to_sale_order/models/__init__.py
-
21pos_order_to_sale_order/models/pos_config.py
-
103pos_order_to_sale_order/models/sale_order.py
-
23pos_order_to_sale_order/models/sale_order_line.py
-
2pos_order_to_sale_order/readme/CONFIGURE.rst
-
38pos_order_to_sale_order/readme/DESCRIPTION.rst
-
11pos_order_to_sale_order/readme/ROADMAP.rst
-
23pos_order_to_sale_order/readme/USAGE.rst
-
BINpos_order_to_sale_order/static/description/pos_config_form.png
-
BINpos_order_to_sale_order/static/description/pos_create_picking_confirm.png
-
BINpos_order_to_sale_order/static/description/pos_create_picking_option_1.png
-
BINpos_order_to_sale_order/static/description/pos_create_picking_option_2.png
-
BINpos_order_to_sale_order/static/description/pos_create_picking_option_3.png
-
BINpos_order_to_sale_order/static/description/pos_frontend_buttons.png
-
BINpos_order_to_sale_order/static/description/pos_frontend_order.png
-
12pos_order_to_sale_order/static/src/css/pos_order_to_sale_order.css
-
225pos_order_to_sale_order/static/src/js/pos_order_to_sale_order.js
-
163pos_order_to_sale_order/static/src/js/screens.js
-
36pos_order_to_sale_order/static/src/xml/pos_order_to_sale_order.xml
-
11pos_order_to_sale_order/views/assets.xml
-
14pos_order_to_sale_order/views/pos_order_to_sale_order.xml
-
66pos_order_to_sale_order/views/view_pos_config.xml
@ -1,2 +1 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
from . import models |
from . import models |
@ -1,22 +1,20 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
{ |
{ |
||||
"name": "PoS Order To Sale Order", |
"name": "PoS Order To Sale Order", |
||||
"version": "8.0.3.0.0", |
|
||||
|
"version": "12.0.1.0.0", |
||||
"author": "GRAP,Odoo Community Association (OCA)", |
"author": "GRAP,Odoo Community Association (OCA)", |
||||
"category": "Point Of Sale", |
"category": "Point Of Sale", |
||||
"license": "AGPL-3", |
"license": "AGPL-3", |
||||
"depends": ["point_of_sale",], |
|
||||
|
"depends": ["point_of_sale"], |
||||
"maintainers": ["legalsylvain"], |
"maintainers": ["legalsylvain"], |
||||
"development_status": "Production/Stable", |
"development_status": "Production/Stable", |
||||
"website": "https://odoo-community.org/", |
|
||||
|
"website": "https://github.com/OCA/pos", |
||||
"data": [ |
"data": [ |
||||
"views/view_pos_config.xml", |
"views/view_pos_config.xml", |
||||
"views/pos_order_to_sale_order.xml", |
|
||||
|
"views/assets.xml", |
||||
], |
], |
||||
"demo": ["demo/res_groups.xml",], |
|
||||
"qweb": ["static/src/xml/pos_order_to_sale_order.xml",], |
|
||||
|
"qweb": ["static/src/xml/pos_order_to_sale_order.xml"], |
||||
} |
} |
@ -1,7 +0,0 @@ |
|||||
<openerp><data> |
|
||||
|
|
||||
<record id="sale.group_discount_per_so_line" model="res.groups"> |
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/> |
|
||||
</record> |
|
||||
|
|
||||
</data></openerp> |
|
@ -1,3 +1,3 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
from . import sale_order |
from . import sale_order |
||||
|
from . import sale_order_line |
||||
from . import pos_config |
from . import pos_config |
@ -1,90 +1,61 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
from openerp import models, api, _ |
|
||||
|
from odoo import _, api, models |
||||
|
|
||||
|
|
||||
class SaleOrder(models.Model): |
class SaleOrder(models.Model): |
||||
_inherit = "sale.order" |
_inherit = "sale.order" |
||||
|
|
||||
@api.model |
@api.model |
||||
def _prepare_order_field_from_pos(self, order_data): |
|
||||
session_obj = self.env["pos.session"] |
|
||||
session = session_obj.browse(order_data["pos_session_id"]) |
|
||||
res = self.onchange_partner_id(order_data["partner_id"])["value"] |
|
||||
res.update( |
|
||||
{ |
|
||||
"partner_id": order_data["partner_id"] or False, |
|
||||
|
def _prepare_from_pos(self, order_data): |
||||
|
PosSession = self.env["pos.session"] |
||||
|
session = PosSession.browse(order_data["pos_session_id"]) |
||||
|
return { |
||||
|
"partner_id": order_data["partner_id"], |
||||
"origin": _("Point of Sale %s") % (session.name), |
"origin": _("Point of Sale %s") % (session.name), |
||||
"client_order_ref": order_data["name"], |
"client_order_ref": order_data["name"], |
||||
"user_id": order_data["user_id"] or False, |
|
||||
"order_line": [], |
|
||||
|
"user_id": order_data["user_id"], |
||||
|
"pricelist_id": order_data["pricelist_id"], |
||||
|
"fiscal_position_id": order_data["fiscal_position_id"], |
||||
} |
} |
||||
) |
|
||||
if self.env.context.get("is_pos_pricelist"): |
|
||||
res.update( |
|
||||
{"pricelist_id": order_data["pricelist_id"],} |
|
||||
) |
|
||||
for line_data in order_data["lines"]: |
|
||||
res["order_line"].append( |
|
||||
[ |
|
||||
0, |
|
||||
False, |
|
||||
self._prepare_order_line_field_from_pos(line_data[2], res), |
|
||||
] |
|
||||
) |
|
||||
return res |
|
||||
|
|
||||
@api.model |
@api.model |
||||
def _prepare_order_line_field_from_pos(self, line_data, sale_order_data): |
|
||||
line_obj = self.env["sale.order.line"] |
|
||||
res = line_obj.product_id_change( |
|
||||
sale_order_data["pricelist_id"], |
|
||||
line_data["product_id"], |
|
||||
qty=line_data["qty"], |
|
||||
partner_id=sale_order_data["partner_id"], |
|
||||
)["value"] |
|
||||
res.update( |
|
||||
{ |
|
||||
"product_id": line_data["product_id"], |
|
||||
"product_uom_qty": line_data["qty"], |
|
||||
"discount": line_data["discount"], |
|
||||
"tax_id": [(6, False, res["tax_id"])], |
|
||||
} |
|
||||
) |
|
||||
if self.env.context.get("is_pos_pricelist"): |
|
||||
res.update( |
|
||||
{ |
|
||||
"price_unit": line_data["price_unit"], |
|
||||
"tax_id": line_data["tax_ids"], |
|
||||
} |
|
||||
) |
|
||||
return res |
|
||||
|
def create_order_from_pos(self, order_data, action): |
||||
|
SaleOrderLine = self.env["sale.order.line"] |
||||
|
|
||||
@api.model |
|
||||
def create_order_from_pos(self, order_data): |
|
||||
is_pos_pricelist = len( |
|
||||
self.env["ir.module.module"].search( |
|
||||
[("name", "=", "pos_pricelist"), ("state", "=", "installed")] |
|
||||
) |
|
||||
) |
|
||||
# Create Draft Sale order |
# Create Draft Sale order |
||||
sale_order = self.create( |
|
||||
self.with_context( |
|
||||
is_pos_pricelist=is_pos_pricelist |
|
||||
)._prepare_order_field_from_pos(order_data) |
|
||||
) |
|
||||
|
order_vals = self._prepare_from_pos(order_data) |
||||
|
sale_order = self.create(order_vals.copy()) |
||||
|
sale_order.onchange_partner_id() |
||||
|
# we rewrite data, because onchange could alter some |
||||
|
# custom data (like pricelist) |
||||
|
sale_order.write(order_vals) |
||||
|
|
||||
|
# create Sale order lines |
||||
|
for order_line_data in order_data["lines"]: |
||||
|
# Create Sale order lines |
||||
|
order_line_vals = SaleOrderLine._prepare_from_pos( |
||||
|
sale_order, order_line_data[2]) |
||||
|
sale_order_line = SaleOrderLine.create( |
||||
|
order_line_vals.copy()) |
||||
|
sale_order_line.product_id_change() |
||||
|
# we rewrite data, because onchange could alter some |
||||
|
# data (like quantity, or price) |
||||
|
sale_order_line.write(order_line_vals) |
||||
|
|
||||
# Confirm Sale Order |
# Confirm Sale Order |
||||
if order_data["sale_order_state"] in ["confirmed", "delivered"]: |
|
||||
sale_order.action_button_confirm() |
|
||||
|
if action in ["confirmed", "delivered"]: |
||||
|
sale_order.action_confirm() |
||||
|
|
||||
# mark picking as delivered |
# mark picking as delivered |
||||
if order_data["sale_order_state"] == "delivered": |
|
||||
sale_order.picking_ids.force_assign() |
|
||||
sale_order.picking_ids.do_transfer() |
|
||||
|
if action == "delivered": |
||||
|
# Mark all moves are delivered |
||||
|
for move in sale_order.mapped( |
||||
|
"picking_ids.move_ids_without_package"): |
||||
|
move.quantity_done = move.product_uom_qty |
||||
|
sale_order.mapped("picking_ids").button_validate() |
||||
|
|
||||
return { |
return { |
||||
"sale_order_id": sale_order.id, |
"sale_order_id": sale_order.id, |
||||
|
@ -0,0 +1,23 @@ |
|||||
|
# Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) |
||||
|
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import api, models |
||||
|
|
||||
|
|
||||
|
class SaleOrderLine(models.Model): |
||||
|
_inherit = "sale.order.line" |
||||
|
|
||||
|
@api.model |
||||
|
def _prepare_from_pos(self, sale_order, order_line_data): |
||||
|
ProductProduct = self.env["product.product"] |
||||
|
product = ProductProduct.browse(order_line_data["product_id"]) |
||||
|
return { |
||||
|
"order_id": sale_order.id, |
||||
|
"product_id": order_line_data["product_id"], |
||||
|
"name": product.name, |
||||
|
"product_uom_qty": order_line_data["qty"], |
||||
|
"discount": order_line_data["discount"], |
||||
|
"price_unit": order_line_data["price_unit"], |
||||
|
"tax_id": order_line_data["tax_ids"], |
||||
|
} |
@ -1,11 +0,0 @@ |
|||||
* Because of the poor design of the Odoo Point of Sale, some basic features |
|
||||
are not available by default, like pricelist, fiscal position, etc ... |
|
||||
For that reason, unit price will be recomputed by default, when creating the |
|
||||
sale order, and the unit price of the current bill will not be used. |
|
||||
|
|
||||
Note that this problem is fixed if ``pos_pricelist`` is installed. |
|
||||
(same repository) In that cases, the pricelist, the unit prices and the taxes |
|
||||
will be the same in the order, as in the displayed bill. |
|
||||
|
|
||||
.. figure:: ../static/description/pos_create_picking_confirm.png |
|
||||
:width: 800 px |
|
@ -0,0 +1,23 @@ |
|||||
|
* Open your Point of sale |
||||
|
* create a new order and select products |
||||
|
* select a customer |
||||
|
|
||||
|
* then, click on the "Create Sale Order" button |
||||
|
|
||||
|
.. figure:: ../static/description/pos_frontend_order.png |
||||
|
:width: 800 px |
||||
|
|
||||
|
Three options are available: |
||||
|
|
||||
|
* **Create a draft Order** |
||||
|
A new sale order in a draft mode will be created that can be changed later. |
||||
|
|
||||
|
* **Create a Confirmed Order** |
||||
|
A new sale order will be created and confirmed. |
||||
|
|
||||
|
* **Create Delivered Picking** (by default) |
||||
|
A new sale order will be created and confirmed. the associated picking |
||||
|
will be marked as delivered. |
||||
|
|
||||
|
.. figure:: ../static/description/pos_frontend_buttons.png |
||||
|
:width: 800 px |
Before Width: 841 | Height: 427 | Size: 38 KiB After Width: 990 | Height: 414 | Size: 37 KiB |
Before Width: 513 | Height: 423 | Size: 28 KiB |
Before Width: 420 | Height: 277 | Size: 20 KiB |
Before Width: 415 | Height: 274 | Size: 21 KiB |
Before Width: 422 | Height: 279 | Size: 20 KiB |
After Width: 585 | Height: 346 | Size: 18 KiB |
After Width: 435 | Height: 332 | Size: 36 KiB |
@ -1,12 +0,0 @@ |
|||||
/* |
|
||||
Copyright (C) 2018 - Today: GRAP (http://www.grap.coop) |
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
*/ |
|
||||
|
|
||||
/*Redefine here, the style defined in web module (base.css), because this file |
|
||||
is not loaded in the point of sale.*/ |
|
||||
.blockUI.blockOverlay { |
|
||||
background-color: black; |
|
||||
opacity: 0.6; |
|
||||
} |
|
@ -1,225 +0,0 @@ |
|||||
/* *************************************************************************** |
|
||||
Copyright (C) 2017 - Today: GRAP (http://www.grap.coop)
|
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
||||
**************************************************************************** */ |
|
||||
|
|
||||
openerp.pos_order_to_sale_order = function (instance) { |
|
||||
|
|
||||
"use strict"; |
|
||||
|
|
||||
var module = instance.point_of_sale; |
|
||||
var _t = instance.web._t; |
|
||||
|
|
||||
/* ************************************************************************ |
|
||||
New Widget CreateSaleOrderButtonWidget |
|
||||
************************************************************************ */ |
|
||||
module.CreateSaleOrderButtonWidget = module.PosBaseWidget.extend({ |
|
||||
template: 'CreateSaleOrderButtonWidget', |
|
||||
|
|
||||
/** |
|
||||
* Define all the confirmation messages. |
|
||||
*/ |
|
||||
init: function (parent, options) { |
|
||||
this._super(parent, options); |
|
||||
this.sale_order_state = options.sale_order_state; |
|
||||
if (this.sale_order_state === 'draft') { |
|
||||
this.display_text = _t("Create Draft Order"); |
|
||||
this.confirmation_message = _t( |
|
||||
'Create Draft Sale Order and discard the current' + |
|
||||
' PoS Order?'); |
|
||||
this.confirmation_comment = _t( |
|
||||
"This operation will permanently discard the current PoS" + |
|
||||
" Order and create a draft Sale Order, based on the" + |
|
||||
" current order lines."); |
|
||||
} else if (options.sale_order_state === 'confirmed') { |
|
||||
this.display_text = _t("Create Confirmed Order"); |
|
||||
this.confirmation_message = _t( |
|
||||
'Create Confirmed Sale Order and discard the current' + |
|
||||
' PoS Order?'); |
|
||||
this.confirmation_comment = _t( |
|
||||
"This operation will permanently discard the current PoS" + |
|
||||
" Order and create a confirmed Sale Order, based on the" + |
|
||||
" current order lines."); |
|
||||
} else if (options.sale_order_state === 'delivered') { |
|
||||
this.display_text = _t("Create Delivered Order"); |
|
||||
this.confirmation_message = _t( |
|
||||
'Create Delivered Sale Order and discard the current' + |
|
||||
' PoS Order?'); |
|
||||
this.confirmation_comment = _t( |
|
||||
"This operation will permanently discard the current PoS" + |
|
||||
" Order and create a confirmed Sale Order, based on the" + |
|
||||
" current order lines. The according picking will be" + |
|
||||
" marked as delivered."); |
|
||||
} |
|
||||
if (! this.pos.pricelist_engine) { |
|
||||
this.confirmation_comment += _t( |
|
||||
"\nNote if you have manually changed unit prices for" + |
|
||||
" some products, this changes will not been taken into" + |
|
||||
" account in the sale order.") |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* Define onclick function when the button to create sale order is |
|
||||
* clicked. |
|
||||
* - On click, check if there is a customer defined, |
|
||||
* - ask confirmation call server to create sale order, and delete |
|
||||
* the current order. |
|
||||
*/ |
|
||||
renderElement: function () { |
|
||||
var self = this; |
|
||||
this._super(); |
|
||||
this.$el.click(function () { |
|
||||
var current_order = self.pos.get('selectedOrder'); |
|
||||
// Prevent empty delivery order
|
|
||||
if (current_order.get('orderLines').length === 0) { |
|
||||
self.pos_widget.screen_selector.show_popup('error', { |
|
||||
'message': _t('Empty Order'), |
|
||||
'comment': _t( |
|
||||
'There must be at least one product in your' + |
|
||||
' order to create Sale Order.'), |
|
||||
}); |
|
||||
return; |
|
||||
} |
|
||||
// Check Customer
|
|
||||
if (!current_order.get('client')) { |
|
||||
self.pos_widget.screen_selector.show_popup('error', { |
|
||||
'message': _t('No customer defined'), |
|
||||
'comment': _t( |
|
||||
'You should select a customer in order to create' + |
|
||||
' a Sale Order. Please select one by clicking' + |
|
||||
' the order tab.'), |
|
||||
}); |
|
||||
return; |
|
||||
} |
|
||||
self.pos.pos_widget.screen_selector.show_popup('confirm', { |
|
||||
message: self.confirmation_message, |
|
||||
comment: self.confirmation_comment, |
|
||||
confirm: function () { |
|
||||
var SaleOrderModel = |
|
||||
new instance.web.Model('sale.order'); |
|
||||
current_order.sale_order_state = self.sale_order_state; |
|
||||
instance.web.blockUI(); |
|
||||
SaleOrderModel.call('create_order_from_pos', [ |
|
||||
self.prepare_create_sale_order(current_order)] |
|
||||
).then(function (result) { |
|
||||
instance.web.unblockUI(); |
|
||||
self.hook_create_sale_order_success(result); |
|
||||
}).fail(function (error, event) { |
|
||||
instance.web.unblockUI(); |
|
||||
self.hook_create_sale_order_error(error, event); |
|
||||
}); |
|
||||
}, |
|
||||
}); |
|
||||
}); |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* Overloadable function to send custom sale order data to server |
|
||||
*/ |
|
||||
prepare_create_sale_order: function (order) { |
|
||||
var res = order.export_as_JSON(); |
|
||||
res.sale_order_state = this.sale_order_state; |
|
||||
return res; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* Overloadable function to make custom action after Sale order |
|
||||
* Creation succeeded |
|
||||
*/ |
|
||||
hook_create_sale_order_success: function (result) { |
|
||||
this.pos.get('selectedOrder').destroy(); |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* Overloadable function to make custom action after Sale order |
|
||||
* Creation failed |
|
||||
*/ |
|
||||
hook_create_sale_order_error: function (error, event) { |
|
||||
event.preventDefault(); |
|
||||
if (error.code === 200) { |
|
||||
// Business Logic Error, not a connection problem
|
|
||||
this.pos_widget.screen_selector.show_popup('error-traceback', { |
|
||||
message: error.data.message, |
|
||||
comment: error.data.debug, |
|
||||
}); |
|
||||
} else { |
|
||||
// Connexion problem
|
|
||||
this.pos_widget.screen_selector.show_popup('error', { |
|
||||
message: _t('The order could not be sent'), |
|
||||
comment: _t( |
|
||||
'Check your internet connection and try again.'), |
|
||||
}); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
}); |
|
||||
|
|
||||
|
|
||||
/* ************************************************************************ |
|
||||
Extend PosWidget: |
|
||||
************************************************************************ */ |
|
||||
module.PosWidget = module.PosWidget.extend({ |
|
||||
|
|
||||
/** |
|
||||
* Overload build_widgets(), to create new buttons, depending of the |
|
||||
* configuration |
|
||||
*/ |
|
||||
build_widgets: function () { |
|
||||
this._super(); |
|
||||
if (this.pos.config.iface_create_draft_sale_order) { |
|
||||
this.create_draft_sale_order_button = |
|
||||
new module.CreateSaleOrderButtonWidget( |
|
||||
this, {'sale_order_state': 'draft'}); |
|
||||
this.create_draft_sale_order_button.appendTo( |
|
||||
this.pos_widget.$('ul.orderlines')); |
|
||||
} |
|
||||
if (this.pos.config.iface_create_confirmed_sale_order) { |
|
||||
this.create_confirmed_sale_order_button = |
|
||||
new module.CreateSaleOrderButtonWidget( |
|
||||
this, {'sale_order_state': 'confirmed'}); |
|
||||
this.create_confirmed_sale_order_button.appendTo( |
|
||||
this.pos_widget.$('ul.orderlines')); |
|
||||
} |
|
||||
if (this.pos.config.iface_create_delivered_sale_order) { |
|
||||
this.create_delivered_sale_order_button = |
|
||||
new module.CreateSaleOrderButtonWidget( |
|
||||
this, {'sale_order_state': 'delivered'}); |
|
||||
this.create_delivered_sale_order_button.appendTo( |
|
||||
this.pos_widget.$('ul.orderlines')); |
|
||||
} |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
|
|
||||
/* ************************************************************************ |
|
||||
Extend OrderWidget |
|
||||
************************************************************************ */ |
|
||||
module.OrderWidget = module.OrderWidget.extend({ |
|
||||
|
|
||||
/** |
|
||||
* Overload renderElement(), to display buttons when the order change. |
|
||||
*/ |
|
||||
renderElement: function (scrollbottom) { |
|
||||
this._super(scrollbottom); |
|
||||
if (this.pos_widget.create_draft_sale_order_button) { |
|
||||
this.pos_widget.create_draft_sale_order_button.appendTo( |
|
||||
this.pos_widget.$('ul.orderlines') |
|
||||
); |
|
||||
} |
|
||||
if (this.pos_widget.create_confirmed_sale_order_button) { |
|
||||
this.pos_widget.create_confirmed_sale_order_button.appendTo( |
|
||||
this.pos_widget.$('ul.orderlines') |
|
||||
); |
|
||||
} |
|
||||
if (this.pos_widget.create_delivered_sale_order_button) { |
|
||||
this.pos_widget.create_delivered_sale_order_button.appendTo( |
|
||||
this.pos_widget.$('ul.orderlines') |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
}; |
|
@ -0,0 +1,163 @@ |
|||||
|
/** *************************************************************************** |
||||
|
Copyright (C) 2017 - Today: GRAP (http://www.grap.coop)
|
||||
|
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
******************************************************************************/ |
||||
|
|
||||
|
odoo.define('pos_order_to_sale_order.screens', function (require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var screens = require('point_of_sale.screens'); |
||||
|
var gui = require('point_of_sale.gui'); |
||||
|
var core = require('web.core'); |
||||
|
var framework = require('web.framework'); |
||||
|
var rpc = require('web.rpc'); |
||||
|
var _t = core._t; |
||||
|
|
||||
|
/** ********************************************************************** |
||||
|
New Widget CreateSaleOrderButtonWidget: |
||||
|
* On click, display a new screen to select the action to do |
||||
|
*/ |
||||
|
var CreateSaleOrderButtonWidget = screens.ActionButtonWidget.extend({ |
||||
|
template: 'CreateSaleOrderButtonWidget', |
||||
|
|
||||
|
button_click: function () { |
||||
|
if (this.pos.get_order().get_client()) { |
||||
|
this.gui.show_screen('create_sale_order'); |
||||
|
} else { |
||||
|
this.gui.show_popup('error', { |
||||
|
'title': _t('No customer defined'), |
||||
|
'body': _t( |
||||
|
'You should select a customer in order to create' + |
||||
|
' a Sale Order.'), |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
is_visible: function () { |
||||
|
return this.pos.get_order().orderlines.length > 0; |
||||
|
}, |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
screens.define_action_button({ |
||||
|
'name': 'create_sale_order', |
||||
|
'widget': CreateSaleOrderButtonWidget, |
||||
|
'condition': function () { |
||||
|
return this.pos.config.iface_create_sale_order; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
screens.OrderWidget.include({ |
||||
|
update_summary: function () { |
||||
|
this._super(); |
||||
|
if (this.getParent().action_buttons && |
||||
|
this.getParent().action_buttons.create_sale_order) { |
||||
|
this.getParent().action_buttons.create_sale_order.renderElement(); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
/** ********************************************************************** |
||||
|
New ScreenWidget CreateSaleOrderScreenWidget: |
||||
|
* On show, display all buttons, depending on the pos configuration |
||||
|
*/ |
||||
|
var CreateSaleOrderScreenWidget = screens.ScreenWidget.extend({ |
||||
|
template: 'CreateSaleOrderScreenWidget', |
||||
|
auto_back: true, |
||||
|
|
||||
|
|
||||
|
show: function(){ |
||||
|
var self = this; |
||||
|
this._super(); |
||||
|
|
||||
|
this.renderElement(); |
||||
|
|
||||
|
this.$('.back').click(function(){ |
||||
|
self.gui.back(); |
||||
|
}); |
||||
|
|
||||
|
if (!this.pos.config.iface_create_draft_sale_order) { |
||||
|
this.$('#button-create-draft-order').addClass('oe_hidden'); |
||||
|
} |
||||
|
if (!this.pos.config.iface_create_confirmed_sale_order) { |
||||
|
this.$('#button-create-confirmed-order').addClass('oe_hidden'); |
||||
|
} |
||||
|
if (!this.pos.config.iface_create_delivered_sale_order) { |
||||
|
this.$('#button-create-delivered-order').addClass('oe_hidden'); |
||||
|
} |
||||
|
|
||||
|
this.$('.paymentmethod').click(function(event){ |
||||
|
self.click_sale_order_button(event.currentTarget.attributes.action.nodeValue); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
click_sale_order_button: function(action) { |
||||
|
var self = this; |
||||
|
console.log("click_sale_order_button : " + action); |
||||
|
|
||||
|
this.gui.show_popup('confirm', { |
||||
|
'title': _t( |
||||
|
'Create Sale Order and discard the current' + |
||||
|
' PoS Order?'), |
||||
|
'body': _t( |
||||
|
"This operation will permanently discard the current PoS" + |
||||
|
" Order and create a Sale Order, based on the" + |
||||
|
" current order lines."), |
||||
|
confirm: function(){ |
||||
|
framework.blockUI(); |
||||
|
rpc.query({ |
||||
|
model: 'sale.order', |
||||
|
method: 'create_order_from_pos', |
||||
|
args: [self.pos.get('selectedOrder').export_as_JSON(), action], |
||||
|
}).then(function (result) { |
||||
|
self.hook_create_sale_order_success(result); |
||||
|
}).fail(function (error, event) { |
||||
|
self.hook_create_sale_order_error(error, event); |
||||
|
}); |
||||
|
}, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Overloadable function to make custom action after Sale order |
||||
|
* Creation succeeded |
||||
|
*/ |
||||
|
hook_create_sale_order_success: function (result) { |
||||
|
framework.unblockUI(); |
||||
|
this.pos.get('selectedOrder').destroy(); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Overloadable function to make custom action after Sale order |
||||
|
* Creation failed |
||||
|
*/ |
||||
|
hook_create_sale_order_error: function (error, event) { |
||||
|
framework.unblockUI(); |
||||
|
event.preventDefault(); |
||||
|
if (error.code === 200) { |
||||
|
// Business Logic Error, not a connection problem
|
||||
|
this.gui.show_popup('error-traceback', { |
||||
|
'title': error.data.message, |
||||
|
'body': error.data.debug, |
||||
|
}); |
||||
|
} else { |
||||
|
// Connexion problem
|
||||
|
this.gui.show_popup('error', { |
||||
|
'title': _t('The order could not be sent'), |
||||
|
'body': _t('Check your internet connection and try again.'), |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
gui.define_screen({ |
||||
|
'name': 'create_sale_order', |
||||
|
'widget': CreateSaleOrderScreenWidget, |
||||
|
'condition': function () { |
||||
|
return this.pos.config.iface_create_sale_order; |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
}); |
@ -0,0 +1,11 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
|
||||
|
<odoo> |
||||
|
|
||||
|
<template id="assets" inherit_id="point_of_sale.assets"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/pos_order_to_sale_order/static/src/js/screens.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
</odoo> |
@ -1,14 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
|
|
||||
<openerp><data> |
|
||||
|
|
||||
<template id="assets_backend" name="pos_order_to_sale_order assets" inherit_id="point_of_sale.index"> |
|
||||
<xpath expr="." position="inside"> |
|
||||
<script type="text/javascript" src="/pos_order_to_sale_order/static/src/js/pos_order_to_sale_order.js"></script> |
|
||||
</xpath> |
|
||||
<xpath expr="//link[@id='pos-stylesheet']" position="after"> |
|
||||
<link rel="stylesheet" href="/pos_order_to_sale_order/static/src/css/pos_order_to_sale_order.css"/> |
|
||||
</xpath> |
|
||||
</template> |
|
||||
|
|
||||
</data></openerp> |
|
@ -1,16 +1,66 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<openerp><data> |
|
||||
|
<odoo> |
||||
|
|
||||
<record id="view_pos_config_form" model="ir.ui.view"> |
<record id="view_pos_config_form" model="ir.ui.view"> |
||||
<field name="model">pos.config</field> |
<field name="model">pos.config</field> |
||||
<field name="inherit_id" ref="point_of_sale.view_pos_config_form"/> |
|
||||
|
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/> |
||||
<field name="arch" type="xml"> |
<field name="arch" type="xml"> |
||||
<field name="iface_invoicing" position="after"> |
|
||||
<field name="iface_create_draft_sale_order" /> |
|
||||
<field name="iface_create_confirmed_sale_order" /> |
|
||||
<field name="iface_create_delivered_sale_order" /> |
|
||||
</field> |
|
||||
|
|
||||
|
<xpath expr="//h2[@name='order']" position="before"> |
||||
|
|
||||
|
<h2 name="create_sale_order">Sale Order Creations</h2> |
||||
|
<div class="row mt16 o_settings_container"> |
||||
|
<div class="col-12 col-lg-6 o_setting_box"> |
||||
|
<div class="o_setting_left_pane"> |
||||
|
<field name="iface_create_draft_sale_order"/> |
||||
|
</div> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label for="iface_create_draft_sale_order"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-12 col-lg-6 o_setting_box"> |
||||
|
<div class="o_setting_left_pane"> |
||||
|
<field name="iface_create_confirmed_sale_order"/> |
||||
|
</div> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label for="iface_create_confirmed_sale_order"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-12 col-lg-6 o_setting_box"> |
||||
|
<div class="o_setting_left_pane"> |
||||
|
<field name="iface_create_delivered_sale_order"/> |
||||
|
</div> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label for="iface_create_delivered_sale_order"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</xpath> |
||||
</field> |
</field> |
||||
</record> |
</record> |
||||
|
</odoo> |
||||
|
|
||||
|
<!-- string="Create Delivered Sale Orders" --> |
||||
|
|
||||
|
|
||||
|
<!-- <div class="text-muted"> |
||||
|
Display pictures of product categories |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
<xpath expr="//field[@name='iface_cashdrawer']/.." position="after"> |
||||
|
<div class="row"> |
||||
|
<label string="Create Draft Sale Orders" for="iface_create_draft_sale_order" class="col-lg-3 o_light_label"/> |
||||
|
<field name="iface_create_draft_sale_order"/> |
||||
|
</div> |
||||
|
<div class="row"> |
||||
|
<label string="Create Confirmed Sale Orders" for="iface_create_confirmed_sale_order" class="col-lg-3 o_light_label"/> |
||||
|
<field name="iface_create_confirmed_sale_order"/> |
||||
|
</div> |
||||
|
<div class="row"> |
||||
|
<label string="Create Delivered Sale Orders" for="iface_create_delivered_sale_order" class="col-lg-3 o_light_label"/> |
||||
|
<field name="iface_create_delivered_sale_order"/> |
||||
|
</div> --> |
||||
|
|
||||
</data></openerp> |
|