[MERGE] forward port branch 9.0 up to 5bed95f
This commit is contained in:
@@ -63,3 +63,9 @@ class AccountInvoiceLine(models.Model):
|
|||||||
fields.Date.today(), company_id=self.company_id.id)
|
fields.Date.today(), company_id=self.company_id.id)
|
||||||
self.account_analytic_id = rec.analytic_id.id
|
self.account_analytic_id = rec.analytic_id.id
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def _set_additional_fields(self, invoice):
|
||||||
|
rec = self.env['account.analytic.default'].account_get(self.product_id.id, self.invoice_id.partner_id.id, self.env.uid,
|
||||||
|
fields.Date.today(), company_id=self.company_id.id)
|
||||||
|
self.account_analytic_id = rec.analytic_id.id
|
||||||
|
super(AccountInvoiceLine, self)._set_additional_fields(invoice)
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Employee">
|
<form string="Employee">
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_button_box" name="button_box" groups="base.group_hr_user">
|
<div class="oe_button_box" name="button_box">
|
||||||
<button name="toggle_active" type="object"
|
<button name="toggle_active" type="object" groups="base.group_hr_user"
|
||||||
class="oe_stat_button" icon="fa-archive">
|
class="oe_stat_button" icon="fa-archive">
|
||||||
<field name="active" widget="boolean_button"
|
<field name="active" widget="boolean_button"
|
||||||
options='{"terminology": "archive"}'/>
|
options='{"terminology": "archive"}'/>
|
||||||
|
|||||||
@@ -394,7 +394,8 @@
|
|||||||
<button name="%(act_hr_employee_payslip_list)d"
|
<button name="%(act_hr_employee_payslip_list)d"
|
||||||
class="oe_stat_button"
|
class="oe_stat_button"
|
||||||
icon="fa-money"
|
icon="fa-money"
|
||||||
type="action">
|
type="action"
|
||||||
|
groups="base.group_hr_user">
|
||||||
<field name="payslip_count" widget="statinfo" string="Payslips"/>
|
<field name="payslip_count" widget="statinfo" string="Payslips"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -402,6 +402,15 @@ class Product(osv.osv):
|
|||||||
class Invoice(osv.osv):
|
class Invoice(osv.osv):
|
||||||
_inherit = 'account.invoice'
|
_inherit = 'account.invoice'
|
||||||
|
|
||||||
|
def action_cancel_draft(self, cr, uid, ids, context=None):
|
||||||
|
member_line_obj = self.pool.get('membership.membership_line')
|
||||||
|
for invoice in self.browse(cr, uid, ids, context=context):
|
||||||
|
mlines = member_line_obj.search(cr, uid,
|
||||||
|
[('account_invoice_line', 'in',
|
||||||
|
[l.id for l in invoice.invoice_line])])
|
||||||
|
member_line_obj.write(cr, uid, mlines, {'date_cancel': False}, context=context)
|
||||||
|
return super(Invoice, self).action_cancel_draft(cr, uid, ids, context=context)
|
||||||
|
|
||||||
def action_cancel(self, cr, uid, ids, context=None):
|
def action_cancel(self, cr, uid, ids, context=None):
|
||||||
'''Create a 'date_cancel' on the membership_line object'''
|
'''Create a 'date_cancel' on the membership_line object'''
|
||||||
member_line_obj = self.pool.get('membership.membership_line')
|
member_line_obj = self.pool.get('membership.membership_line')
|
||||||
|
|||||||
@@ -285,6 +285,13 @@ class product_pricelist_item(osv.osv):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _get_product_pricelist(self, cr, uid, ids, context=None):
|
||||||
|
result = set()
|
||||||
|
for pricelist in self.pool['product.pricelist'].browse(cr, uid, ids, context=context):
|
||||||
|
for item in pricelist.item_ids:
|
||||||
|
result.add(item.id)
|
||||||
|
return list(result)
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', help="Specify a template if this rule only applies to one product template. Keep empty otherwise."),
|
'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', help="Specify a template if this rule only applies to one product template. Keep empty otherwise."),
|
||||||
'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help="Specify a product if this rule only applies to one product. Keep empty otherwise."),
|
'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help="Specify a product if this rule only applies to one product. Keep empty otherwise."),
|
||||||
@@ -315,9 +322,13 @@ class product_pricelist_item(osv.osv):
|
|||||||
'price_max_margin': fields.float('Max. Price Margin',
|
'price_max_margin': fields.float('Max. Price Margin',
|
||||||
digits_compute= dp.get_precision('Product Price'), help='Specify the maximum amount of margin over the base price.'),
|
digits_compute= dp.get_precision('Product Price'), help='Specify the maximum amount of margin over the base price.'),
|
||||||
'company_id': fields.related('pricelist_id','company_id',type='many2one',
|
'company_id': fields.related('pricelist_id','company_id',type='many2one',
|
||||||
readonly=True, relation='res.company', string='Company', store=True),
|
readonly=True, relation='res.company', string='Company', store={
|
||||||
|
'product.pricelist': (_get_product_pricelist, ['company_id'], 30),
|
||||||
|
}),
|
||||||
'currency_id': fields.related('pricelist_id', 'currency_id', type='many2one',
|
'currency_id': fields.related('pricelist_id', 'currency_id', type='many2one',
|
||||||
readonly=True, relation='res.currency', string='Currency', store=True),
|
readonly=True, relation='res.currency', string='Currency', store={
|
||||||
|
'product.pricelist': (_get_product_pricelist, ['currency_id'], 30),
|
||||||
|
}),
|
||||||
'date_start': fields.date('Start Date', help="Starting date for the pricelist item validation"),
|
'date_start': fields.date('Start Date', help="Starting date for the pricelist item validation"),
|
||||||
'date_end': fields.date('End Date', help="Ending valid for the pricelist item validation"),
|
'date_end': fields.date('End Date', help="Ending valid for the pricelist item validation"),
|
||||||
'compute_price': fields.selection([('fixed', 'Fix Price'), ('percentage', 'Percentage (discount)'), ('formula', 'Formula')], select=True, default='fixed'),
|
'compute_price': fields.selection([('fixed', 'Fix Price'), ('percentage', 'Percentage (discount)'), ('formula', 'Formula')], select=True, default='fixed'),
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ class AccountInvoice(models.Model):
|
|||||||
valuation_price_unit_total += val_stock_move.price_unit * val_stock_move.product_qty
|
valuation_price_unit_total += val_stock_move.price_unit * val_stock_move.product_qty
|
||||||
valuation_total_qty += val_stock_move.product_qty
|
valuation_total_qty += val_stock_move.product_qty
|
||||||
valuation_price_unit = valuation_price_unit_total / valuation_total_qty
|
valuation_price_unit = valuation_price_unit_total / valuation_total_qty
|
||||||
|
valuation_price_unit = self.env['product.uom']._compute_price(i_line.product_id.uom_id.id, valuation_price_unit, i_line.uom_id.id)
|
||||||
if inv.currency_id.id != company_currency.id:
|
if inv.currency_id.id != company_currency.id:
|
||||||
valuation_price_unit = company_currency.with_context(date=inv.date_invoice).compute(valuation_price_unit, inv.currency_id)
|
valuation_price_unit = company_currency.with_context(date=inv.date_invoice).compute(valuation_price_unit, inv.currency_id)
|
||||||
if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
|
if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
|
||||||
|
|||||||
@@ -164,16 +164,24 @@ function parse_value (value, descriptor, value_if_empty) {
|
|||||||
if (datetime.isValid())
|
if (datetime.isValid())
|
||||||
return time.datetime_to_str(datetime.toDate());
|
return time.datetime_to_str(datetime.toDate());
|
||||||
datetime = moment(value, [date_pattern + ' ' + time_pattern, date_pattern_wo_zero + ' ' + time_pattern_wo_zero, moment.ISO_8601]);
|
datetime = moment(value, [date_pattern + ' ' + time_pattern, date_pattern_wo_zero + ' ' + time_pattern_wo_zero, moment.ISO_8601]);
|
||||||
if (datetime.isValid())
|
if (datetime.isValid()) {
|
||||||
|
if (datetime.year() === 0) {
|
||||||
|
datetime.year(moment.utc().year());
|
||||||
|
}
|
||||||
return time.datetime_to_str(datetime.toDate());
|
return time.datetime_to_str(datetime.toDate());
|
||||||
|
}
|
||||||
throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value));
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value));
|
||||||
case 'date':
|
case 'date':
|
||||||
var date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601], true);
|
var date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601], true);
|
||||||
if (date.isValid())
|
if (date.isValid())
|
||||||
return time.date_to_str(date.toDate());
|
return time.date_to_str(date.toDate());
|
||||||
date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601]);
|
date = moment(value, [date_pattern, date_pattern_wo_zero, moment.ISO_8601]);
|
||||||
if (date.isValid())
|
if (date.isValid()) {
|
||||||
|
if (date.year() === 0) {
|
||||||
|
date.year(moment.utc().year());
|
||||||
|
}
|
||||||
return time.date_to_str(date.toDate());
|
return time.date_to_str(date.toDate());
|
||||||
|
}
|
||||||
throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value));
|
throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value));
|
||||||
case 'time':
|
case 'time':
|
||||||
var _time = moment(value, [time_pattern, time_pattern_wo_zero, moment.ISO_8601], true);
|
var _time = moment(value, [time_pattern, time_pattern_wo_zero, moment.ISO_8601], true);
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ var TranslationDataBase = Class.extend(/** @lends instance.TranslationDataBase#
|
|||||||
});
|
});
|
||||||
if (translation_bundle.lang_parameters) {
|
if (translation_bundle.lang_parameters) {
|
||||||
this.parameters = translation_bundle.lang_parameters;
|
this.parameters = translation_bundle.lang_parameters;
|
||||||
if (typeof(py) !== "undefined") {
|
this.parameters.grouping = JSON.parse(this.parameters.grouping);
|
||||||
this.parameters.grouping = py.eval(this.parameters.grouping);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
add_module_translation: function(mod) {
|
add_module_translation: function(mod) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class website_config_settings(osv.osv_memory):
|
|||||||
'website_name': fields.related('website_id', 'name', type="char", string="Website Name"),
|
'website_name': fields.related('website_id', 'name', type="char", string="Website Name"),
|
||||||
|
|
||||||
'language_ids': fields.related('website_id', 'language_ids', type='many2many', relation='res.lang', string='Languages'),
|
'language_ids': fields.related('website_id', 'language_ids', type='many2many', relation='res.lang', string='Languages'),
|
||||||
'default_lang_id': fields.related('website_id', 'default_lang_id', type='many2one', relation='res.lang', string='Default language'),
|
'default_lang_id': fields.related('website_id', 'default_lang_id', type='many2one', relation='res.lang', string='Default language', required=True),
|
||||||
'default_lang_code': fields.related('website_id', 'default_lang_code', type="char", string="Default language code"),
|
'default_lang_code': fields.related('website_id', 'default_lang_code', type="char", string="Default language code"),
|
||||||
'google_analytics_key': fields.related('website_id', 'google_analytics_key', type="char", string='Google Analytics Key'),
|
'google_analytics_key': fields.related('website_id', 'google_analytics_key', type="char", string='Google Analytics Key'),
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ class website(osv.osv):
|
|||||||
'domain': fields.char('Website Domain'),
|
'domain': fields.char('Website Domain'),
|
||||||
'company_id': fields.many2one('res.company', string="Company"),
|
'company_id': fields.many2one('res.company', string="Company"),
|
||||||
'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'),
|
'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'),
|
||||||
'default_lang_id': fields.many2one('res.lang', string="Default language"),
|
'default_lang_id': fields.many2one('res.lang', string="Default language", required=True),
|
||||||
'default_lang_code': fields.related('default_lang_id', 'code', type="char", string="Default language code", store=True),
|
'default_lang_code': fields.related('default_lang_id', 'code', type="char", string="Default language code", store=True),
|
||||||
'social_twitter': fields.char('Twitter Account'),
|
'social_twitter': fields.char('Twitter Account'),
|
||||||
'social_facebook': fields.char('Facebook Account'),
|
'social_facebook': fields.char('Facebook Account'),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<div name="button_box" position="inside">
|
<div name="button_box" position="inside">
|
||||||
<button class="oe_stat_button" name="website_publish_button"
|
<button class="oe_stat_button" name="website_publish_button"
|
||||||
type="object" icon="fa-globe">
|
type="object" icon="fa-globe" groups="base.group_hr_user">
|
||||||
<field name="website_published" widget="website_button"/>
|
<field name="website_published" widget="website_button"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -73,11 +73,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
|
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
|
||||||
<label class="control-label" for="contact_name">Your Name</label>
|
<label class="control-label" for="name">Your Name</label>
|
||||||
<input type="text" name="name" class="form-control" t-att-value="name or partner.name" />
|
<input type="text" name="name" class="form-control" t-att-value="name or partner.name" />
|
||||||
</div>
|
</div>
|
||||||
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
|
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
|
||||||
<label class="control-label" for="contact_name">Email</label>
|
<label class="control-label" for="email">Email</label>
|
||||||
<input type="email" name="email" class="form-control" t-att-value="email or partner.email" />
|
<input type="email" name="email" class="form-control" t-att-value="email or partner.email" />
|
||||||
</div>
|
</div>
|
||||||
<div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6">
|
<div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6">
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ odoo.define('website_sale.website_sale', function (require) {
|
|||||||
|
|
||||||
var ajax = require('web.ajax');
|
var ajax = require('web.ajax');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
|
var utils = require('web.utils');
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
var base = require('web_editor.base');
|
var base = require('web_editor.base');
|
||||||
|
|
||||||
@@ -250,9 +251,15 @@ $('.oe_website_sale').each(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function price_to_str(price) {
|
function price_to_str(price) {
|
||||||
price = Math.round(price * 100) / 100;
|
var l10n = _t.database.parameters;
|
||||||
var dec = Math.round((price % 1) * 100);
|
var precision = 2;
|
||||||
return price + (dec ? '' : '.0') + (dec%10 ? '' : '0');
|
|
||||||
|
if ($(".decimal_precision").length) {
|
||||||
|
precision = parseInt($(".decimal_precision").first().data('precision'));
|
||||||
|
}
|
||||||
|
var formatted = _.str.sprintf('%.' + precision + 'f', price).split('.');
|
||||||
|
formatted[0] = utils.insert_thousand_seps(formatted[0]);
|
||||||
|
return formatted.join(l10n.decimal_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(oe_website_sale).on('change', 'input.js_product_change', function () {
|
$(oe_website_sale).on('change', 'input.js_product_change', function () {
|
||||||
|
|||||||
@@ -439,7 +439,7 @@
|
|||||||
<span itemprop="price" style="display:none;" t-esc="product.price"/>
|
<span itemprop="price" style="display:none;" t-esc="product.price"/>
|
||||||
<span itemprop="priceCurrency" style="display:none;" t-esc="website.currency_id.name"/>
|
<span itemprop="priceCurrency" style="display:none;" t-esc="website.currency_id.name"/>
|
||||||
</h4>
|
</h4>
|
||||||
<h4 class="css_non_editable_mode_hidden">
|
<h4 class="css_non_editable_mode_hidden decimal_precision" t-att-data-precision="product.currency_id.decimal_places">
|
||||||
<span t-field="product.lst_price"
|
<span t-field="product.lst_price"
|
||||||
t-field-options='{
|
t-field-options='{
|
||||||
"widget": "monetary",
|
"widget": "monetary",
|
||||||
@@ -977,7 +977,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
|
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
|
||||||
<label class="control-label" for="contact_name">Your Name</label>
|
<label class="control-label" for="name">Your Name</label>
|
||||||
<input type="text" name="name" class="form-control" t-att-value="checkout.get('name')"/>
|
<input type="text" name="name" class="form-control" t-att-value="checkout.get('name')"/>
|
||||||
</div>
|
</div>
|
||||||
<div t-if="has_check_vat" class="clearfix"/>
|
<div t-if="has_check_vat" class="clearfix"/>
|
||||||
@@ -990,7 +990,7 @@
|
|||||||
<input type="text" name="vat" class="form-control" t-att-value="checkout.get('vat')"/>
|
<input type="text" name="vat" class="form-control" t-att-value="checkout.get('vat')"/>
|
||||||
</div>
|
</div>
|
||||||
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
|
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
|
||||||
<label class="control-label" for="contact_name">Email</label>
|
<label class="control-label" for="email">Email</label>
|
||||||
<input type="email" name="email" class="form-control" t-att-value="checkout.get('email')"/>
|
<input type="email" name="email" class="form-control" t-att-value="checkout.get('email')"/>
|
||||||
</div>
|
</div>
|
||||||
<div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6">
|
<div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6">
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Spain, 2016-11-21
|
||||||
|
|
||||||
|
Diagram Software, S.L. agrees to the terms of the Odoo Corporate Contributor License
|
||||||
|
Agreement v1.0.
|
||||||
|
|
||||||
|
I declare that I am authorized and able to make this agreement and sign this
|
||||||
|
declaration.
|
||||||
|
|
||||||
|
Signed,
|
||||||
|
|
||||||
|
Jose Zambudio jose.zambudio@diagram.es https://github.com/zamberjo
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
|
||||||
|
Cristian Moncho cristian.moncho@diagram.es https://github.com/crimoniv
|
||||||
|
Jose Zambudio jose.zambudio@diagram.es https://github.com/zamberjo
|
||||||
|
Almudena de la Puente almudena.delapuente@diagram.es https://github.com/almumu
|
||||||
|
Mauro Cebriá mauro.cebria@diagram.es https://github.com/maurochip
|
||||||
|
Pedro Albujer pedro.albujer.rico@diagram.es https://github.com/P4R
|
||||||
|
Rubén Cerdà ruben.cerda.roig@diagram.es https://github.com/rubencr7
|
||||||
@@ -10,7 +10,7 @@ import urllib2
|
|||||||
import urlparse
|
import urlparse
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from odoo import api, fields, models, tools, _
|
from odoo import api, fields, models, tools, SUPERUSER_ID, _
|
||||||
from odoo.modules import get_module_resource
|
from odoo.modules import get_module_resource
|
||||||
from odoo.osv.expression import get_unaccent_wrapper
|
from odoo.osv.expression import get_unaccent_wrapper
|
||||||
from odoo.exceptions import UserError, ValidationError
|
from odoo.exceptions import UserError, ValidationError
|
||||||
@@ -478,8 +478,12 @@ class Partner(models.Model, FormatAddress):
|
|||||||
if len(companies) > 1 or company not in companies:
|
if len(companies) > 1 or company not in companies:
|
||||||
raise UserError(_("You can not change the company as the partner/user has multiple user linked with different companies."))
|
raise UserError(_("You can not change the company as the partner/user has multiple user linked with different companies."))
|
||||||
tools.image_resize_images(vals)
|
tools.image_resize_images(vals)
|
||||||
|
result = True
|
||||||
result = super(Partner, self).write(vals)
|
# To write in SUPERUSER on field is_company and avoid access rights problems.
|
||||||
|
if 'is_company' in vals and self.user_has_groups('base.group_partner_manager') and not self.env.uid == SUPERUSER_ID:
|
||||||
|
result = super(Partner, self).sudo().write({'is_company': vals.get('is_company')})
|
||||||
|
del vals['is_company']
|
||||||
|
result = result and super(Partner, self).write(vals)
|
||||||
for partner in self:
|
for partner in self:
|
||||||
if any(u.has_group('base.group_user') for u in partner.user_ids if u != self.env.user):
|
if any(u.has_group('base.group_user') for u in partner.user_ids if u != self.env.user):
|
||||||
self.env['res.users'].check_access_rights('write')
|
self.env['res.users'].check_access_rights('write')
|
||||||
|
|||||||
@@ -1126,6 +1126,8 @@ def formatLang(env, value, digits=None, grouping=True, monetary=False, dp=False,
|
|||||||
if dp:
|
if dp:
|
||||||
decimal_precision_obj = env['decimal.precision']
|
decimal_precision_obj = env['decimal.precision']
|
||||||
digits = decimal_precision_obj.precision_get(dp)
|
digits = decimal_precision_obj.precision_get(dp)
|
||||||
|
elif currency_obj:
|
||||||
|
digits = currency_obj.decimal_places
|
||||||
elif (hasattr(value, '_field') and isinstance(value._field, (float_field, function_field)) and value._field.digits):
|
elif (hasattr(value, '_field') and isinstance(value._field, (float_field, function_field)) and value._field.digits):
|
||||||
digits = value._field.digits[1]
|
digits = value._field.digits[1]
|
||||||
if not digits and digits is not 0:
|
if not digits and digits is not 0:
|
||||||
|
|||||||
Reference in New Issue
Block a user