From e9d8189cb1daa8aa450ac9cd1ad080f7b1727080 Mon Sep 17 00:00:00 2001 From: ralwafaie Date: Wed, 13 Apr 2016 10:14:08 +0200 Subject: [PATCH 1/2] Sale Payment Method - Payment Acquirer Module --- .../README.rst | 35 +++++++++++++++++++ .../__init__.py | 9 +++++ .../__openerp__.py | 33 +++++++++++++++++ .../controller.py | 22 ++++++++++++ .../payment_acquirer.py | 13 +++++++ .../payment_acquirer_view.xml | 15 ++++++++ .../payment_method.py | 14 ++++++++ .../payment_method_view.xml | 26 ++++++++++++++ .../payment_transaction.py | 30 ++++++++++++++++ sale_payment_method_payment_acquirer/sale.py | 18 ++++++++++ .../sale_view.xml | 15 ++++++++ 11 files changed, 230 insertions(+) create mode 100644 sale_payment_method_payment_acquirer/README.rst create mode 100644 sale_payment_method_payment_acquirer/__init__.py create mode 100644 sale_payment_method_payment_acquirer/__openerp__.py create mode 100644 sale_payment_method_payment_acquirer/controller.py create mode 100644 sale_payment_method_payment_acquirer/payment_acquirer.py create mode 100644 sale_payment_method_payment_acquirer/payment_acquirer_view.xml create mode 100644 sale_payment_method_payment_acquirer/payment_method.py create mode 100644 sale_payment_method_payment_acquirer/payment_method_view.xml create mode 100644 sale_payment_method_payment_acquirer/payment_transaction.py create mode 100644 sale_payment_method_payment_acquirer/sale.py create mode 100644 sale_payment_method_payment_acquirer/sale_view.xml diff --git a/sale_payment_method_payment_acquirer/README.rst b/sale_payment_method_payment_acquirer/README.rst new file mode 100644 index 000000000000..e2ba1a84dadc --- /dev/null +++ b/sale_payment_method_payment_acquirer/README.rst @@ -0,0 +1,35 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +====================================== +Sale Payment Method - Payment Acquirer +====================================== + +* this module adds acquirer_id to sale payment method and links between them + +Installation +============ + +* No thing is required to install this module + +Contributors +------------ + +* Katja Matthes +* Rami Alwafaie + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. \ No newline at end of file diff --git a/sale_payment_method_payment_acquirer/__init__.py b/sale_payment_method_payment_acquirer/__init__.py new file mode 100644 index 000000000000..c0441e965c60 --- /dev/null +++ b/sale_payment_method_payment_acquirer/__init__.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import payment_method +from . import payment_acquirer +from . import payment_transaction +from . import sale +from . import controller diff --git a/sale_payment_method_payment_acquirer/__openerp__.py b/sale_payment_method_payment_acquirer/__openerp__.py new file mode 100644 index 000000000000..e36a69632f17 --- /dev/null +++ b/sale_payment_method_payment_acquirer/__openerp__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Sale Payment Method - Payment Acquirer", + "version": "8.0.1.0.0", + "depends": ["payment", + "sale_payment_method", + "sale", + "website_sale", + ], + 'author': 'initOS GmbH, Odoo Community Association (OCA)', + "category": "", + "summary": "", + 'license': 'AGPL-3', + "description": """ +Sale Payment Method - Payment Acquirer +======================================= +* this module adds acquirer_id to sale payment method + """, + 'data': ['payment_method_view.xml', + 'payment_acquirer_view.xml', + 'sale_view.xml', + ], + 'images': [], + 'demo': [ + ], + 'test': [ + ], + 'installable': True, + 'auto_install': False, +} diff --git a/sale_payment_method_payment_acquirer/controller.py b/sale_payment_method_payment_acquirer/controller.py new file mode 100644 index 000000000000..5a3cbbff6136 --- /dev/null +++ b/sale_payment_method_payment_acquirer/controller.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.addons.website_sale.controllers.main import website_sale +from openerp import http +from openerp.http import request, route + + +class website_sale_customization(website_sale): + + # change the payment method if we choose the acquirer id from the website + @http.route(['/shop/payment/transaction/'], type='json', auth="public", website=True) + def payment_transaction(self, acquirer_id): + + res = super(website_sale_customization, self).payment_transaction(acquirer_id) + if acquirer_id: + cr, uid, context, registry = request.cr, request.uid, request.context, request.registry + order = request.website.sale_get_order(context=context) + order.onchange_payment_acquirer_id() + order.onchange_payment_method_set_workflow() + return res diff --git a/sale_payment_method_payment_acquirer/payment_acquirer.py b/sale_payment_method_payment_acquirer/payment_acquirer.py new file mode 100644 index 000000000000..9562678236e7 --- /dev/null +++ b/sale_payment_method_payment_acquirer/payment_acquirer.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields + + +class PaymentAcquirer(models.Model): + _inherit = 'payment.acquirer' + + payment_method_id = fields.Many2one('payment.method', + 'Payment Method', + ) diff --git a/sale_payment_method_payment_acquirer/payment_acquirer_view.xml b/sale_payment_method_payment_acquirer/payment_acquirer_view.xml new file mode 100644 index 000000000000..91b59340e422 --- /dev/null +++ b/sale_payment_method_payment_acquirer/payment_acquirer_view.xml @@ -0,0 +1,15 @@ + + + + + paymennt.acquirer.extension_method.view_form + payment.acquirer + + + + + + + + + \ No newline at end of file diff --git a/sale_payment_method_payment_acquirer/payment_method.py b/sale_payment_method_payment_acquirer/payment_method.py new file mode 100644 index 000000000000..8eee9dea16b1 --- /dev/null +++ b/sale_payment_method_payment_acquirer/payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields + + +class PaymentMethod(models.Model): + _inherit = 'payment.method' + + acquirer_id = fields.One2many('payment.acquirer', + 'payment_method_id', + 'Acquirer', + required=False,) diff --git a/sale_payment_method_payment_acquirer/payment_method_view.xml b/sale_payment_method_payment_acquirer/payment_method_view.xml new file mode 100644 index 000000000000..b43b0fda50f2 --- /dev/null +++ b/sale_payment_method_payment_acquirer/payment_method_view.xml @@ -0,0 +1,26 @@ + + + + + sale.acquirer.extension_method.view_form + payment.method + + + + + + + + + + sale_acquirer_extension.payment_method.view_tree + payment.method + + + + + + + + + diff --git a/sale_payment_method_payment_acquirer/payment_transaction.py b/sale_payment_method_payment_acquirer/payment_transaction.py new file mode 100644 index 000000000000..99d62502f320 --- /dev/null +++ b/sale_payment_method_payment_acquirer/payment_transaction.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models +from openerp import SUPERUSER_ID + + +class PaymentTransaction(models.Model): + _inherit = 'payment.transaction' + + def form_feedback(self, cr, uid, data, acquirer_name, context=None): + """ Override to create automatic payments for order, if transaction is done. """ + + res = super(PaymentTransaction, self).form_feedback(cr, uid, data, acquirer_name, context=context) + # Order already confirmed. (cmp. module website_sale) + + tx = None + # fetch the tx, check its state, confirm the potential SO + tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name + if hasattr(self, tx_find_method_name): + tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context) + if tx and tx.state == 'done' and tx.sale_order_id: + self.pool['sale.order'].automatic_payment(cr, + SUPERUSER_ID, + [tx.sale_order_id.id], + context=context, + amount=tx.amount) + + return res diff --git a/sale_payment_method_payment_acquirer/sale.py b/sale_payment_method_payment_acquirer/sale.py new file mode 100644 index 000000000000..7aba595d4a54 --- /dev/null +++ b/sale_payment_method_payment_acquirer/sale.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, api + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + @api.onchange('payment_acquirer_id') + def onchange_payment_acquirer_id(self): + #change payment method according to payment_acquirer_id + if not self.payment_acquirer_id: + return + method = self.payment_acquirer_id.payment_method_id + if method: + self.payment_method_id = method diff --git a/sale_payment_method_payment_acquirer/sale_view.xml b/sale_payment_method_payment_acquirer/sale_view.xml new file mode 100644 index 000000000000..bc84665c5729 --- /dev/null +++ b/sale_payment_method_payment_acquirer/sale_view.xml @@ -0,0 +1,15 @@ + + + + + sale.order.view_form + sale.order + + + + + + + + + \ No newline at end of file From adcec7576fca5f6d92607ce64e7a1bd6f0487a01 Mon Sep 17 00:00:00 2001 From: ralwafaie Date: Mon, 1 Aug 2016 15:15:42 +0200 Subject: [PATCH 2/2] stock_picking_onhold_module --- stock_picking_on_hold/README.rst | 49 ++++++++ stock_picking_on_hold/__init__.py | 7 ++ stock_picking_on_hold/__openerp__.py | 24 ++++ stock_picking_on_hold/account_invoice.py | 27 ++++ stock_picking_on_hold/payment_method.py | 15 +++ stock_picking_on_hold/stock.py | 117 ++++++++++++++++++ .../views/payment_method.xml | 15 +++ stock_picking_on_hold/views/stock.xml | 27 ++++ 8 files changed, 281 insertions(+) create mode 100644 stock_picking_on_hold/README.rst create mode 100644 stock_picking_on_hold/__init__.py create mode 100644 stock_picking_on_hold/__openerp__.py create mode 100644 stock_picking_on_hold/account_invoice.py create mode 100644 stock_picking_on_hold/payment_method.py create mode 100644 stock_picking_on_hold/stock.py create mode 100644 stock_picking_on_hold/views/payment_method.xml create mode 100644 stock_picking_on_hold/views/stock.xml diff --git a/stock_picking_on_hold/README.rst b/stock_picking_on_hold/README.rst new file mode 100644 index 000000000000..b993a03d41d2 --- /dev/null +++ b/stock_picking_on_hold/README.rst @@ -0,0 +1,49 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License: AGPL-3 + +=================================================== +Sale Payment Method - Hold Pickings (until payment) +=================================================== + +This module allows to hold the picking until the invoice is paid + +Usage +===== + +* go to ... +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/186/8.0 + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Thomas Rehn +* Katja Matthes + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/stock_picking_on_hold/__init__.py b/stock_picking_on_hold/__init__.py new file mode 100644 index 000000000000..2de5b4827449 --- /dev/null +++ b/stock_picking_on_hold/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import account_invoice +from . import payment_method +from . import stock diff --git a/stock_picking_on_hold/__openerp__.py b/stock_picking_on_hold/__openerp__.py new file mode 100644 index 000000000000..c64d9dc6d27e --- /dev/null +++ b/stock_picking_on_hold/__openerp__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{'name': 'Sale Payment Method - Hold Pickings (until payment)', + 'version': '1.0', + 'category': 'Warehouse', + 'description': """ + Sale Payment Method - Hold Pickings (until payment) + =================================================== + * This module allows to hold the picking until the invoice is paid + """, + 'depends': ['stock', + 'sale', + 'sale_payment_method_automatic_workflow', + ], + 'author': "initOS GmbH, Odoo Community Association OCA", + 'license': 'AGPL-3', + 'data': ['views/stock.xml', + 'views/payment_method.xml', + ], + 'installable': True, + 'application': False, + } diff --git a/stock_picking_on_hold/account_invoice.py b/stock_picking_on_hold/account_invoice.py new file mode 100644 index 000000000000..09b9a44feb4a --- /dev/null +++ b/stock_picking_on_hold/account_invoice.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, api + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + @api.multi + def confirm_paid(self): + """ + When an invoice is paid + a picking that is hold until payment may need a status check. + """ + res = super(AccountInvoice, self).confirm_paid() + # collect all pickings to check + pickings_to_check = self.env['stock.picking'] + for invoice in self: + for sale in invoice.sale_ids: + for picking in sale.picking_ids: + if picking.state == 'hold': + pickings_to_check += picking + # trigger availability check + pickings_to_check.action_assign() + return res diff --git a/stock_picking_on_hold/payment_method.py b/stock_picking_on_hold/payment_method.py new file mode 100644 index 000000000000..ad2a249ce88b --- /dev/null +++ b/stock_picking_on_hold/payment_method.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields + + +class PaymentMethod(models.Model): + _inherit = 'payment.method' + + hold_picking_until_payment = fields.Boolean( + string='Hold Picking Until Payment', + help="If set to true, pickings will not be automatically confirmed" + "when the invoice has not been paid." + ) diff --git a/stock_picking_on_hold/stock.py b/stock_picking_on_hold/stock.py new file mode 100644 index 000000000000..51cf1e6c7af0 --- /dev/null +++ b/stock_picking_on_hold/stock.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +# © initOS GmbH 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, api +from openerp.osv import fields + + +class StockMove(models.Model): + _inherit = 'stock.move' + + @api.multi + def action_assign(self): + for move in self: + if move.picking_id: + # Write dummy variable so that the state of the + # picking will be updated. + move.picking_id.dummy_int_to_trigger_state_update = \ + (move.picking_id.dummy_int_to_trigger_state_update + 1) % 2 + if self._context.get('payment_check', True) and \ + move.picking_id.is_on_hold(): + # Do not assign picking because it is on hold + return False + return super(StockMove, self).action_assign() + + +class StockPicking(models.Model): + _inherit = 'stock.picking' + + def _state_get(self, cr, uid, ids, field_name, arg, context=None): + res = super(StockPicking, self).\ + _state_get(cr, uid, ids, field_name, arg, context=context) + pickings = self.browse(cr, uid, res.keys(), context=context) + for picking in pickings: + if res[picking.id] == 'confirmed' and picking.is_on_hold(): + res[picking.id] = 'hold' + return res + + def _get_pickings(self, cr, uid, ids, context=None): + # Method is copied from stock/stock.py. + # Calling _get_pickings of `super(StockPicking, self)` doesn't work + # because when the method is being called, `self` is a stock.move. + res = set() + for move in self.browse(cr, uid, ids, context=context): + if move.picking_id: + res.add(move.picking_id.id) + return list(res) + + _columns = { + 'state': fields.function( + _state_get, + type="selection", + copy=False, + store={ + 'stock.picking': ( + lambda self, cr, uid, ids, ctx: ids, + ['move_type', 'dummy_int_to_trigger_state_update'], 20), + 'stock.move': ( + _get_pickings, + ['state', 'picking_id', 'partially_available'], 20)}, + selection=[ + ('draft', 'Draft'), + ('cancel', 'Cancelled'), + ('waiting', 'Waiting Another Operation'), + ('confirmed', 'Waiting Availability'), + ('partially_available', 'Partially Available'), + ('hold', 'Waiting For Payment'), + ('assigned', 'Ready to Transfer'), + ('done', 'Transferred'), + ], + string='Status', + readonly=True, + select=True, + track_visibility='onchange', + help=""" + * Draft: not confirmed yet and will not be + scheduled until confirmed\n + * Waiting Another Operation: waiting for another move to + proceed before \n + it becomes automatically available + (e.g. in Make-To-Order flows)\n + * Waiting Availability: still waiting for the availability + of products\n + * Waiting For Payment: waiting for the payment + of the related sale order\n + * Partially Available: some products are available and reserved\n + * Ready to Transfer: products reserved, + simply waiting for confirmation.\n + * Transferred: has been processed, + can't be modified or cancelled anymore\n + * Cancelled: has been cancelled, can't be confirmed anymore""" + ), + # In an ideal world "On Hold" would be a computed field that depends on + # the payment status of the sale order. Unfortunately the changes + # to the v7-functional fields 'sale_id.invoiced' don't seem to be + # propagated to the new api.depends mechanism. There we use this ugly + # workaround that forces the re-computation of the state whenever + # action_assign is called. + 'dummy_int_to_trigger_state_update': fields.integer( + string='Dummy Integer (to trigger update of state field)' + ) + } + + @api.multi + def is_on_hold(self): + """Returns True iff picking should be held because the + corresponding order has not been paid yet.""" + self.ensure_one() + if self.sale_id and self.sale_id.payment_method_id and\ + self.sale_id.payment_method_id.hold_picking_until_payment and\ + not self.sale_id.invoiced: + return True + return False + + @api.multi + def action_assign_unpaid(self): + self.with_context(payment_check=False).action_assign() diff --git a/stock_picking_on_hold/views/payment_method.xml b/stock_picking_on_hold/views/payment_method.xml new file mode 100644 index 000000000000..bdcae0289f45 --- /dev/null +++ b/stock_picking_on_hold/views/payment_method.xml @@ -0,0 +1,15 @@ + + + + + sale_payment_method.payment_method.view_form + payment.method + + + + + + + + + \ No newline at end of file diff --git a/stock_picking_on_hold/views/stock.xml b/stock_picking_on_hold/views/stock.xml new file mode 100644 index 000000000000..d9702f30f607 --- /dev/null +++ b/stock_picking_on_hold/views/stock.xml @@ -0,0 +1,27 @@ + + + + + stock.picking.form + stock.picking + + + + confirmed,hold + + +