mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-10-25 07:27:39 -05:00
[PATCH] Upstream patch - 26082022
This commit is contained in:
1 parent
a65d154200
commit
dda9de67b6
12 files changed
+124
-14
No files matched your search
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user