mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2025-02-25 18:55:21 -06:00
[PATCH] Upstream patch - 13072022
This commit is contained in:
@@ -14,15 +14,29 @@ from flectra.tools.translate import _
|
||||
|
||||
from flectra.addons.google_account.models.google_service import GOOGLE_TOKEN_ENDPOINT, TIMEOUT
|
||||
|
||||
from datetime import date
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# Google is depreciating their OOB Auth Flow on 3rd October 2022, the Google Drive
|
||||
# integration thus become irrelevant after that date.
|
||||
|
||||
# https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html#disallowed-oob
|
||||
GOOGLE_AUTH_DEPRECATION_DATE = date(2022, 10, 3)
|
||||
|
||||
|
||||
class GoogleDrive(models.Model):
|
||||
|
||||
_name = 'google.drive.config'
|
||||
_description = "Google Drive templates config"
|
||||
|
||||
def _module_deprecated(self):
|
||||
return GOOGLE_AUTH_DEPRECATION_DATE > fields.Date.today()
|
||||
|
||||
def get_google_drive_url(self, res_id, template_id):
|
||||
if self._module_deprecated():
|
||||
return
|
||||
|
||||
self.ensure_one()
|
||||
self = self.sudo()
|
||||
|
||||
@@ -49,6 +63,9 @@ class GoogleDrive(models.Model):
|
||||
|
||||
@api.model
|
||||
def get_access_token(self, scope=None):
|
||||
if self._module_deprecated():
|
||||
return
|
||||
|
||||
Config = self.env['ir.config_parameter'].sudo()
|
||||
google_drive_refresh_token = Config.get_param('google_drive_refresh_token')
|
||||
user_is_admin = self.env.is_admin()
|
||||
@@ -84,6 +101,9 @@ class GoogleDrive(models.Model):
|
||||
|
||||
@api.model
|
||||
def copy_doc(self, res_id, template_id, name_gdocs, res_model):
|
||||
if self._module_deprecated():
|
||||
return
|
||||
|
||||
google_web_base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
access_token = self.get_access_token()
|
||||
# Copy template in to drive with help of new access token
|
||||
|
||||
@@ -36,6 +36,9 @@ class ResConfigSettings(models.TransientModel):
|
||||
|
||||
def action_setup_token(self):
|
||||
self.ensure_one()
|
||||
if self.env['google.drive.config']._module_deprecated():
|
||||
return
|
||||
|
||||
template = self.env.ref('google_drive.google_drive_auth_code_wizard')
|
||||
return {
|
||||
'name': _('Set up refresh token'),
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
<div id="msg_module_google_drive" position="replace">
|
||||
<div class="content-group"
|
||||
attrs="{'invisible': [('module_google_drive','=',False)]}">
|
||||
<div class="mt8 mb8 text-warning font-weight-bold">
|
||||
This module will stop working after the 3rd October 2022 due to
|
||||
<a href="https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html#disallowed-oob">changes in Google Authentication API</a>.
|
||||
</div>
|
||||
<div class="mt8 row">
|
||||
<div class="col-sm">
|
||||
<field name="is_google_drive_token_generated" invisible="1"/>
|
||||
|
||||
@@ -161,7 +161,7 @@ class AccountMove(models.Model):
|
||||
# To solve this there is a <Arrotondamento> or 'rounding' field, such that:
|
||||
# taxable base = sum(taxable base for each unit) + Arrotondamento
|
||||
tax_details = self._prepare_edi_tax_details(
|
||||
filter_to_apply=lambda l: l['tax_repartition_line_id'].factor_percent > 0
|
||||
filter_to_apply=lambda l: l['tax_repartition_line_id'].factor_percent >= 0
|
||||
)
|
||||
for _tax_name, tax_dict in tax_details['tax_details'].items():
|
||||
base_amount = tax_dict['base_amount_currency']
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<IdPaese>IT</IdPaese>
|
||||
<IdCodice>01234560157</IdCodice>
|
||||
</IdTrasmittente>
|
||||
<ProgressivoInvio>2022030008</ProgressivoInvio>
|
||||
<ProgressivoInvio>___ignore___</ProgressivoInvio>
|
||||
<FormatoTrasmissione>FPR12</FormatoTrasmissione>
|
||||
<CodiceDestinatario>XXXXXXX</CodiceDestinatario>
|
||||
<ContattiTrasmittente>
|
||||
@@ -54,7 +54,7 @@
|
||||
<TipoDocumento>TD01</TipoDocumento>
|
||||
<Divisa>EUR</Divisa>
|
||||
<Data>2022-03-24</Data>
|
||||
<Numero>INV/2022/03/0008</Numero>
|
||||
<Numero>___ignore___</Numero>
|
||||
<ImportoTotaleDocumento>1600.80</ImportoTotaleDocumento>
|
||||
</DatiGeneraliDocumento>
|
||||
</DatiGenerali>
|
||||
@@ -92,7 +92,7 @@
|
||||
<ModalitaPagamento>MP05</ModalitaPagamento>
|
||||
<DataScadenzaPagamento>2022-03-24</DataScadenzaPagamento>
|
||||
<ImportoPagamento>1600.80</ImportoPagamento>
|
||||
<CodicePagamento>INV/2022/03/0008</CodicePagamento>
|
||||
<CodicePagamento>___ignore___</CodicePagamento>
|
||||
</DettaglioPagamento>
|
||||
</DatiPagamento>
|
||||
<Allegati></Allegati>
|
||||
|
||||
@@ -171,7 +171,7 @@ class TestItEdiReverseCharge(TestItEdi):
|
||||
def _test_invoice_with_sample_file(self, invoice, filename, xpaths_file=None, xpaths_result=None):
|
||||
result = self._cleanup_etree(invoice._export_as_xml(), xpaths_result)
|
||||
expected = self._cleanup_etree(self._get_test_file_content(filename), xpaths_file)
|
||||
self.assertXmlTreeEqual(expected, result)
|
||||
self.assertXmlTreeEqual(result, expected)
|
||||
|
||||
def test_reverse_charge_invoice(self):
|
||||
self._test_invoice_with_sample_file(self.reverse_charge_invoice, "reverse_charge_invoice.xml")
|
||||
|
||||
@@ -47,6 +47,36 @@ class TestItEdi(AccountEdiTestCommon):
|
||||
'company_id': cls.company.id,
|
||||
})
|
||||
|
||||
cls.tax_zero_percent_hundred_percent_repartition = cls.env['account.tax'].create({
|
||||
'name': 'all of nothing',
|
||||
'amount': 0,
|
||||
'amount_type': 'percent',
|
||||
'company_id': cls.company.id,
|
||||
'invoice_repartition_line_ids': [
|
||||
(0, 0, {'factor_percent': 100, 'repartition_type': 'base'}),
|
||||
(0, 0, {'factor_percent': 100, 'repartition_type': 'tax'}),
|
||||
],
|
||||
'refund_repartition_line_ids': [
|
||||
(0, 0, {'factor_percent': 100, 'repartition_type': 'base'}),
|
||||
(0, 0, {'factor_percent': 100, 'repartition_type': 'tax'}),
|
||||
],
|
||||
})
|
||||
|
||||
cls.tax_zero_percent_zero_percent_repartition = cls.env['account.tax'].create({
|
||||
'name': 'none of nothing',
|
||||
'amount': 0,
|
||||
'amount_type': 'percent',
|
||||
'company_id': cls.company.id,
|
||||
'invoice_repartition_line_ids': [
|
||||
(0, 0, {'factor_percent': 100, 'repartition_type': 'base'}),
|
||||
(0, 0, {'factor_percent': 0, 'repartition_type': 'tax'}),
|
||||
],
|
||||
'refund_repartition_line_ids': [
|
||||
(0, 0, {'factor_percent': 100, 'repartition_type': 'base'}),
|
||||
(0, 0, {'factor_percent': 0, 'repartition_type': 'tax'}),
|
||||
],
|
||||
})
|
||||
|
||||
cls.italian_partner_a = cls.env['res.partner'].create({
|
||||
'name': 'Alessi',
|
||||
'vat': 'IT00465840031',
|
||||
@@ -261,6 +291,24 @@ class TestItEdi(AccountEdiTestCommon):
|
||||
'private_key': 'l10n_it_edi_sdicoop_test',
|
||||
})
|
||||
|
||||
cls.zero_tax_invoice = cls.env['account.move'].with_company(cls.company).create({
|
||||
'move_type': 'out_invoice',
|
||||
'invoice_date': datetime.date(2022, 3, 24),
|
||||
'partner_id': cls.italian_partner_a.id,
|
||||
'invoice_line_ids': [
|
||||
(0, 0, {
|
||||
**cls.standard_line,
|
||||
'name': 'line with tax of 0% with repartition line of 100% ',
|
||||
'tax_ids': [(6, 0, [cls.tax_zero_percent_hundred_percent_repartition.id])],
|
||||
}),
|
||||
(0, 0, {
|
||||
**cls.standard_line,
|
||||
'name': 'line with tax of 0% with repartition line of 0% ',
|
||||
'tax_ids': [(6, 0, [cls.tax_zero_percent_zero_percent_repartition.id])],
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
# post the invoices
|
||||
cls.price_included_invoice._post()
|
||||
cls.partial_discount_invoice._post()
|
||||
@@ -269,6 +317,7 @@ class TestItEdi(AccountEdiTestCommon):
|
||||
cls.below_400_codice_simplified_invoice._post()
|
||||
cls.total_400_VAT_simplified_invoice._post()
|
||||
cls.pa_partner_invoice._post()
|
||||
cls.zero_tax_invoice._post()
|
||||
|
||||
cls.edi_basis_xml = cls._get_test_file_content('IT00470550013_basis.xml')
|
||||
cls.edi_simplified_basis_xml = cls._get_test_file_content('IT00470550013_simpl.xml')
|
||||
@@ -571,3 +620,51 @@ class TestItEdi(AccountEdiTestCommon):
|
||||
def test_send_pa_partner(self):
|
||||
res = self.edi_format._l10n_it_post_invoices_step_1(self.pa_partner_invoice)
|
||||
self.assertEqual(res[self.pa_partner_invoice], {'attachment': self.pa_partner_invoice.l10n_it_edi_attachment_id, 'success': True})
|
||||
|
||||
def test_zero_percent_taxes(self):
|
||||
invoice_etree = etree.fromstring(self.zero_tax_invoice._export_as_xml())
|
||||
expected_etree = self.with_applied_xpath(
|
||||
etree.fromstring(self.edi_basis_xml),
|
||||
'''
|
||||
<xpath expr="//FatturaElettronicaBody//DatiBeniServizi" position="replace">
|
||||
<DatiBeniServizi>
|
||||
<DettaglioLinee>
|
||||
<NumeroLinea>1</NumeroLinea>
|
||||
<Descrizione>line with tax of 0% with repartition line of 100%</Descrizione>
|
||||
<Quantita>1.00</Quantita>
|
||||
<PrezzoUnitario>800.400000</PrezzoUnitario>
|
||||
<PrezzoTotale>800.40</PrezzoTotale>
|
||||
<AliquotaIVA>0.00</AliquotaIVA>
|
||||
</DettaglioLinee>
|
||||
<DettaglioLinee>
|
||||
<NumeroLinea>2</NumeroLinea>
|
||||
<Descrizione>line with tax of 0% with repartition line of 0%</Descrizione>
|
||||
<Quantita>1.00</Quantita>
|
||||
<PrezzoUnitario>800.400000</PrezzoUnitario>
|
||||
<PrezzoTotale>800.40</PrezzoTotale>
|
||||
<AliquotaIVA>0.00</AliquotaIVA>
|
||||
</DettaglioLinee>
|
||||
<DatiRiepilogo>
|
||||
<AliquotaIVA>0.00</AliquotaIVA>
|
||||
<ImponibileImporto>800.40</ImponibileImporto>
|
||||
<Imposta>0.00</Imposta>
|
||||
<EsigibilitaIVA>I</EsigibilitaIVA>
|
||||
</DatiRiepilogo>
|
||||
<DatiRiepilogo>
|
||||
<AliquotaIVA>0.00</AliquotaIVA>
|
||||
<ImponibileImporto>800.40</ImponibileImporto>
|
||||
<Imposta>0.00</Imposta>
|
||||
<EsigibilitaIVA>I</EsigibilitaIVA>
|
||||
</DatiRiepilogo>
|
||||
</DatiBeniServizi>
|
||||
</xpath>
|
||||
<xpath expr="//DettaglioPagamento//ImportoPagamento" position="inside">
|
||||
1600.80
|
||||
</xpath>
|
||||
<xpath expr="//DatiGeneraliDocumento//ImportoTotaleDocumento" position="inside">
|
||||
1600.80
|
||||
</xpath>
|
||||
'''
|
||||
)
|
||||
invoice_etree = self.with_applied_xpath(invoice_etree, "<xpath expr='.//Allegati' position='replace'/>")
|
||||
self.assertXmlTreeEqual(invoice_etree, expected_etree)
|
||||
|
||||
@@ -13,7 +13,7 @@ echo "addons/point_of_sale/tools/posbox/overwrite_after_init/home/pi/odoo" >> .g
|
||||
git fetch "${localremote}" "${localbranch}" --depth=1
|
||||
git reset "${localremote}"/"${localbranch}" --hard
|
||||
|
||||
git clean -df
|
||||
git clean -dfx
|
||||
cp -a /home/pi/odoo/addons/point_of_sale/tools/posbox/overwrite_after_init/home/pi/odoo/* /home/pi/odoo/
|
||||
rm -r /home/pi/odoo/addons/point_of_sale/tools/posbox/overwrite_after_init
|
||||
|
||||
|
||||
@@ -315,21 +315,10 @@ publicWidget.registry.WebsiteSale = publicWidget.Widget.extend(VariantMixin, {
|
||||
if (!data.cart_quantity) {
|
||||
return window.location = '/shop/cart';
|
||||
}
|
||||
wSaleUtils.updateCartNavBar(data);
|
||||
$input.val(data.quantity);
|
||||
$('.js_quantity[data-line-id='+line_id+']').val(data.quantity).html(data.quantity);
|
||||
|
||||
if (data.warning) {
|
||||
var cart_alert = $('.oe_cart').parent().find('#data_warning');
|
||||
if (cart_alert.length === 0) {
|
||||
$('.oe_cart').prepend('<div class="alert alert-danger alert-dismissable" role="alert" id="data_warning">'+
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning + '</div>');
|
||||
}
|
||||
else {
|
||||
cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning);
|
||||
}
|
||||
$input.val(data.quantity);
|
||||
}
|
||||
wSaleUtils.updateCartNavBar(data);
|
||||
wSaleUtils.showWarning(data.warning);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -45,18 +45,43 @@ function animateClone($cart, $elem, offsetTop, offsetLeft) {
|
||||
* @param {Object} data
|
||||
*/
|
||||
function updateCartNavBar(data) {
|
||||
var $qtyNavBar = $(".my_cart_quantity");
|
||||
_.each($qtyNavBar, function (qty) {
|
||||
var $qty = $(qty);
|
||||
$qty.parents('li:first').removeClass('d-none');
|
||||
$qty.html(data.cart_quantity).hide().fadeIn(600);
|
||||
});
|
||||
$(".my_cart_quantity")
|
||||
.parents('li.o_wsale_my_cart').removeClass('d-none').end()
|
||||
.toggleClass('fa fa-warning', !data.cart_quantity)
|
||||
.attr('title', data.warning)
|
||||
.text(data.cart_quantity || '')
|
||||
.hide()
|
||||
.fadeIn(600);
|
||||
|
||||
$(".js_cart_lines").first().before(data['website_sale.cart_lines']).end().remove();
|
||||
$(".js_cart_summary").first().before(data['website_sale.short_cart_summary']).end().remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays `message` in an alert box at the top of the page if it's a
|
||||
* non-empty string.
|
||||
*
|
||||
* @param {string | null} message
|
||||
*/
|
||||
function showWarning(message) {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
var $page = $('.oe_website_sale');
|
||||
var cart_alert = $page.children('#data_warning');
|
||||
if (!cart_alert.length) {
|
||||
cart_alert = $(
|
||||
'<div class="alert alert-danger alert-dismissible" role="alert" id="data_warning">' +
|
||||
'<button type="button" class="close" data-dismiss="alert">×</button> ' +
|
||||
'<span></span>' +
|
||||
'</div>').prependTo($page);
|
||||
}
|
||||
cart_alert.children('span:last-child').text(message);
|
||||
}
|
||||
|
||||
return {
|
||||
animateClone: animateClone,
|
||||
updateCartNavBar: updateCartNavBar,
|
||||
showWarning: showWarning,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -177,15 +177,9 @@ publicWidget.registry.ProductWishlist = publicWidget.Widget.extend(VariantMixin,
|
||||
add_qty: parseInt(qty_id, 10),
|
||||
display: false,
|
||||
},
|
||||
}).then(function (resp) {
|
||||
if (resp.warning) {
|
||||
if (! $('#data_warning').length) {
|
||||
$('.wishlist-section').prepend('<div class="mt16 alert alert-danger alert-dismissable" role="alert" id="data_warning"></div>');
|
||||
}
|
||||
var cart_alert = $('.wishlist-section').parent().find('#data_warning');
|
||||
cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + resp.warning);
|
||||
}
|
||||
$('.my_cart_quantity').html(resp.cart_quantity || '<i class="fa fa-warning" /> ');
|
||||
}).then(function (data) {
|
||||
wSaleUtils.updateCartNavBar(data);
|
||||
wSaleUtils.showWarning(data.warning);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -30,21 +30,18 @@
|
||||
<blockquote class="small">
|
||||
<h2>How to configure the Twitter API access</h2>
|
||||
<ol>
|
||||
<li>Create a new Twitter application on <a href="https://apps.twitter.com/app/new" target="new">https://apps.twitter.com/app/new</a>
|
||||
with the following values:
|
||||
<li>Log in or create an account on <a href="https://developer.twitter.com/" target="new"> https://developer.twitter.com/</a></li>
|
||||
<li>Once connected, and if not already done, complete the Twitter portal access process on <a href="https://developer.twitter.com/portal/" target="new">https://developer.twitter.com/portal/</a></li>
|
||||
<li>On the <a href="https://developer.twitter.com/portal/" target="new">Twitter Portal</a>, <strong>create a project</strong> with the following information:
|
||||
<ul>
|
||||
<li><strong>Name: </strong> Flectra Twitter Integration</li>
|
||||
<li><strong>Description: </strong> Flectra Twitter Integration </li>
|
||||
<li><strong>Website: </strong>
|
||||
<b><field name="twitter_server_uri" /></b></li>
|
||||
<li><strong>Callback URL: </strong>Leave blank</li>
|
||||
<li>Accept terms of use and click on the Create your Twitter application button at the bottom</li>
|
||||
<li><strong>Use Case: </strong> Embedding Tweets in a website</li>
|
||||
<li><strong>Description: </strong> Flectra Twitter Integration</li>
|
||||
<li><strong>App Name: </strong> choose a unique name</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Switch to the API Keys tab: <br/>
|
||||
<img src='/website_twitter/static/src/img/api_key.png' alt="API Key"/>
|
||||
</li><br/>
|
||||
<li>Copy/Paste Consumer Key (API Key) and Consumer Secret (API Secret) keys below.</li>
|
||||
<li>Copy/Paste the API Key and API Key Secret values into the above fields</li>
|
||||
<li>Get Elevated access by going to <a href="https://developer.twitter.com/en/portal/products" target="new">https://developer.twitter.com/en/portal/products</a>, click on <strong>Elevated</strong> then on <strong>Apply</strong> and finally complete the form.</li>
|
||||
</ol>
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user