[PATCH] Upstream patch - 26082022

This commit is contained in:
Parthiv Patel committed 2022-08-26 08:34:34 +00:00
1 parent a65d154200
commit dda9de67b6
12 files changed
+124 -14

No files matched your search

+2 -2
View File
@@ -100,7 +100,7 @@ class ReSequenceWizard(models.TransientModel):
for move in record.move_ids._origin: # Sort the moves by period depending on the sequence number reset
moves_by_period[_get_move_key(move)] += move
format, format_values = self.env['account.move']._get_sequence_format_param(record.first_name)
seq_format, format_values = record.move_ids[0]._get_sequence_format_param(record.first_name)
new_values = {}
for j, period_recs in enumerate(moves_by_period.values()):
@@ -114,7 +114,7 @@ class ReSequenceWizard(models.TransientModel):
'server-date': str(move.date),
}
new_name_list = [format.format(**{
new_name_list = [seq_format.format(**{
**format_values,
'year': period_recs[0].date.year % (10 ** format_values['year_length']),
'month': period_recs[0].date.month,
@@ -625,6 +625,9 @@ class AccountEdiFormat(models.Model):
:param barcode: The barcode of the product.
:returns: A product or an empty recordset if not found.
'''
if name and '\n' in name:
# cut Sales Description from the name
name = name.split('\n')[0]
domains = []
for value, domain in (
(name, ('name', 'ilike', name)),
@@ -21,6 +21,10 @@
<ram:SellerAssignedID
t-if="line.product_id and line.product_id.default_code"
t-esc="line.product_id.default_code"/>
<!-- TODO:
<ram:Name t-esc="line.product_id.name or line.name"/>
<ram:Description t-esc="line.name" t-if="line.name != line.product_id.name"/>
-->
<ram:Name t-esc="line.name"/>
</ram:SpecifiedTradeProduct>
@@ -324,13 +324,14 @@ class AccountEdiFormat(models.Model):
# Product.
name = _find_value('.//ram:SpecifiedTradeProduct/ram:Name', element)
if name:
invoice_line_form.name = name
invoice_line_form.product_id = self_ctx._retrieve_product(
default_code=_find_value('.//ram:SpecifiedTradeProduct/ram:SellerAssignedID', element),
name=_find_value('.//ram:SpecifiedTradeProduct/ram:Name', element),
barcode=_find_value('.//ram:SpecifiedTradeProduct/ram:GlobalID', element)
)
# force original line description instead of the one copied from product's Sales Description
if name:
invoice_line_form.name = name
# Quantity.
line_elements = element.xpath('.//ram:SpecifiedLineTradeDelivery/ram:BilledQuantity', namespaces=tree.nsmap)
@@ -11,3 +11,15 @@ class StockPicking(models.Model):
if subcontract_move.sale_line_id:
return subcontract_move.sale_line_id.order_id.warehouse_id
return super(StockPicking, self)._get_warehouse(subcontract_move)
def _prepare_subcontract_mo_vals(self, subcontract_move, bom):
res = super()._prepare_subcontract_mo_vals(subcontract_move, bom)
if not res.get('picking_type_id') and subcontract_move.location_dest_id.usage == 'customer':
# If the if-condition is respected, it means that `subcontract_move` is not
# related to a specific warehouse. This can happen if, for instance, the user
# confirms a PO with a subcontracted product that should be delivered to a
# customer (dropshipping). In that case, we can use a default warehouse to
# get the picking type
default_warehouse = self.env['stock.warehouse'].search([('company_id', '=', subcontract_move.company_id.id)], limit=1)
res['picking_type_id'] = default_warehouse.subcontracting_type_id.id,
return res
@@ -134,3 +134,61 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
self.assertEqual(move1.product_uom_qty, 1)
self.assertEqual(move2.product_id, self.comp1)
self.assertEqual(move2.product_uom_qty, 1)
def test_po_to_customer(self):
"""
Create and confirm a PO with a subcontracted move. The picking type of
the PO is 'Dropship' and the delivery address a customer.
"""
subcontractor, client = self.env['res.partner'].create([
{'name': 'SuperSubcontractor'},
{'name': 'SuperClient'},
])
p_finished, p_compo = self.env['product.product'].create([{
'name': 'Finished Product',
'type': 'product',
'seller_ids': [(0, 0, {'name': subcontractor.id})],
}, {
'name': 'Component',
'type': 'consu',
}])
bom = self.env['mrp.bom'].create({
'product_tmpl_id': p_finished.product_tmpl_id.id,
'product_qty': 1,
'type': 'subcontract',
'subcontractor_ids': [(6, 0, subcontractor.ids)],
'bom_line_ids': [
(0, 0, {'product_id': p_compo.id, 'product_qty': 1}),
],
})
dropship_picking_type = self.env['stock.picking.type'].search([
('company_id', '=', self.env.company.id),
('default_location_src_id.usage', '=', 'supplier'),
('default_location_dest_id.usage', '=', 'customer'),
], limit=1, order='sequence')
po = self.env['purchase.order'].create({
"partner_id": subcontractor.id,
"picking_type_id": dropship_picking_type.id,
"dest_address_id": client.id,
"order_line": [(0, 0, {
'product_id': p_finished.id,
'name': p_finished.name,
'product_qty': 1.0,
})],
})
po.button_confirm()
mo = self.env['mrp.production'].search([('bom_id', '=', bom.id)])
self.assertEqual(mo.picking_type_id, self.warehouse.subcontracting_type_id)
delivery = po.picking_ids
delivery.move_line_ids.qty_done = 1.0
delivery.button_validate()
self.assertEqual(delivery.state, 'done')
self.assertEqual(mo.state, 'done')
self.assertEqual(po.order_line.qty_received, 1)
@@ -55,6 +55,13 @@ class StripeController(http.Controller):
def stripe_s2s_process_payment_intent(self, **post):
return request.env['payment.transaction'].sudo().form_feedback(post, 'stripe')
@http.route('/payment/stripe/s2s/process_payment_error', type='json', auth='public', csrf=False)
def stripe_s2s_process_payment_error(self, **post):
transaction_sudo = request.env['payment.transaction'].sudo().search([('reference', '=', post['reference']),
('provider', '=', 'stripe'),
('stripe_payment_intent_secret', '=', post['stripe_payment_intent_secret'])])
transaction_sudo.write({'state': 'error', 'state_message': post['error']})
@http.route('/payment/stripe/webhook', type='json', auth='public', csrf=False)
def stripe_webhook(self, **kwargs):
data = json.loads(request.httprequest.data)
@@ -22,7 +22,12 @@ return PaymentProcessing.include({
return stripe.handleCardPayment(tx.stripe_payment_intent_secret)
.then(function(result) {
if (result.error) {
return Promise.reject({"message": {"data": { "message": result.error.message}}});
return rpc.query({
route: '/payment/stripe/s2s/process_payment_error',
params: _.extend({}, {reference: tx.reference,
stripe_payment_intent_secret: tx.stripe_payment_intent_secret,
error: result.error.message})
}).then(()=> Promise.reject({"message": {"data": { "message": result.error.message}}}));
}
return rpc.query({
route: '/payment/stripe/s2s/process_payment_intent',
@@ -45,7 +45,14 @@ var DateTimePicker = function ($, moment) {
EVENT_KEY = '.' + DATA_KEY,
DATA_API_KEY = '.data-api',
Selector = {
DATA_TOGGLE: '[data-toggle="' + DATA_KEY + '"]'
// /!\ FLECTRA PATCH: ensure the datetimepickers can be toggled only after
// the Flectra lazy loader finished loading all lazy scripts. Another
// solution could have been to temporarily removing the data-toggle
// attributes during lazyloading but that would not have been stable as
// custom code could search for data-toggle elements while the lazy
// loading is being performed. Without this, clicking too soon on a
// datetimepicker would not use the right format and UI options.
DATA_TOGGLE: 'body:not(.o_lazy_js_waiting) [data-toggle="' + DATA_KEY + '"]'
},
ClassName = {
INPUT: NAME + '-input'
@@ -10,7 +10,7 @@ var blockFunction = function (ev) {
var waitingLazy = false;
/**
* Blocks the DOM sections which explicitely require the lazy loaded JS to be
* Blocks the DOM sections which explicitly require the lazy loaded JS to be
* working (those sections should be marked with the 'o_wait_lazy_js' class).
*
* @see stopWaitingLazy
@@ -28,6 +28,8 @@ function waitLazy() {
element.addEventListener(evType, blockFunction);
});
}
document.body.classList.add('o_lazy_js_waiting');
}
/**
* Unblocks the DOM sections blocked by @see waitLazy and removes the related
@@ -47,6 +49,8 @@ function stopWaitingLazy() {
});
element.classList.remove('o_wait_lazy_js');
}
document.body.classList.remove('o_lazy_js_waiting');
}
// Start waiting for lazy loading as soon as the DOM is available
@@ -26,6 +26,9 @@ const GalleryWidget = publicWidget.Widget.extend({
* @param {Event} ev
*/
_onClickImg: function (ev) {
if (this.$modal) {
return;
}
var self = this;
var $cur = $(ev.currentTarget);
@@ -43,29 +46,30 @@ const GalleryWidget = publicWidget.Widget.extend({
var $img = ($cur.is('img') === true) ? $cur : $cur.closest('img');
const milliseconds = $cur.closest('.s_image_gallery').data('interval') || false;
var $modal = $(qweb.render('website.gallery.slideshow.lightbox', {
this.$modal = $(qweb.render('website.gallery.slideshow.lightbox', {
images: $images.get(),
index: $images.index($img),
dim: dimensions,
interval: milliseconds || 0,
id: _.uniqueId('slideshow_'),
}));
$modal.modal({
this.$modal.modal({
keyboard: true,
backdrop: true,
});
$modal.on('hidden.bs.modal', function () {
this.$modal.on('hidden.bs.modal', function () {
$(this).hide();
$(this).siblings().filter('.modal-backdrop').remove(); // bootstrap leaves a modal-backdrop
$(this).remove();
self.$modal = undefined;
});
$modal.find('.modal-content, .modal-body.o_slideshow').css('height', '100%');
$modal.appendTo(document.body);
this.$modal.find('.modal-content, .modal-body.o_slideshow').css('height', '100%');
this.$modal.appendTo(document.body);
$modal.one('shown.bs.modal', function () {
this.$modal.one('shown.bs.modal', function () {
self.trigger_up('widgets_start_request', {
editableMode: false,
$target: $modal.find('.modal-body.o_slideshow'),
$target: self.$modal.find('.modal-body.o_slideshow'),
});
});
},
@@ -63,6 +63,11 @@
}
}
}
@include media-breakpoint-up(sm) {
#o_wevent_index_main_col article div.col {
min-width: 0;
}
}
&.opt_event_list_cards_bg {
@if (color('body') == $o-portal-default-body-bg) {
@extend .bg-200;