Merge branch 'develop'

Permitir repetir productos al facturar
This commit is contained in:
Mauricio Baeza 2018-02-09 20:38:46 -06:00
commit bb3f6d3aed
8 changed files with 76 additions and 66 deletions

View File

@ -313,7 +313,10 @@ class SendMail(object):
message.attach(MIMEText(options['mensaje'], 'html'))
for f in options['files']:
part = MIMEBase('application', 'octet-stream')
part.set_payload(f[0])
if isinstance(f[0], str):
part.set_payload(f[0].encode('utf-8'))
else:
part.set_payload(f[0])
encoders.encode_base64(part)
part.add_header(
'Content-Disposition',

View File

@ -1061,24 +1061,23 @@ class LIBO(object):
self._template.setPrinter(self._set_properties({'PaperFormat': LETTER}))
self._render(data)
# ~ path = '{}.ods'.format(tempfile.mkstemp()[1])
path = get_path_temp('.ods')
self._template.storeToURL(self._path_url(path), ())
path_ods = get_path_temp('.ods')
self._template.storeToURL(self._path_url(path_ods), ())
if ods:
data = self._read(path)
_kill(path)
data = self._read(path_ods)
_kill(path_ods)
return data
doc = self._doc_open(path, {'Hidden': True})
doc = self._doc_open(path_ods, {'Hidden': True})
options = {'FilterName': 'calc_pdf_Export'}
# ~ path = tempfile.mkstemp()[1]
path = get_path_temp('.pdf')
doc.storeToURL(self._path_url(path), self._set_properties(options))
path_pdf = get_path_temp('.pdf')
doc.storeToURL(self._path_url(path_pdf), self._set_properties(options))
doc.close(True)
self._template.close(True)
data = self._read(path)
_kill(path)
data = self._read(path_pdf)
_kill(path_ods)
_kill(path_pdf)
return data
def _get_data(self, doc, name=0):
@ -1674,7 +1673,8 @@ def _nomina(doc, data, values, version_cfdi):
info = CaseInsensitiveDict(node_nomina.attrib.copy())
node = node_nomina.find('{}Emisor'.format(PRE['NOMINA'][version]))
data['emisor'].update(CaseInsensitiveDict(node.attrib.copy()))
if not node is None:
data['emisor'].update(CaseInsensitiveDict(node.attrib.copy()))
node = node_nomina.find('{}Receptor'.format(PRE['NOMINA'][version]))
data['receptor'].update(CaseInsensitiveDict(node.attrib.copy()))

View File

@ -136,44 +136,31 @@ def import_invoice():
if not rows:
return {'ok': False, 'msg': msg}
# ~ clave, descripcion, precio, cantidad
products = {}
products = []
for row in rows:
try:
obj = Productos.get(Productos.clave==row[0])
if obj.id in products:
vu = round(row[2], 2)
descuento = round(row[3], 2)
cant = round(row[4], 2)
pf = products[obj.id]['valor_unitario'] - descuento
products[obj.id]['cantidad'] += cant
products[obj.id]['importe'] = round(
pf * products[obj.id]['cantidad'], DECIMALES)
if vu != products[obj.id]['valor_unitario']:
msg = 'Precio diferente en producto: {}'.format(row[0])
return {'ok': False, 'msg': msg}
else:
vu = round(row[2], 2)
descuento = round(row[3], 2)
cant = round(row[4], 2)
pf = vu - descuento
p = {
'id': obj.id,
'delete': '-',
'clave': obj.clave,
'descripcion': obj.descripcion,
'unidad': obj.unidad.name,
'cantidad': cant,
'valor_unitario': vu,
'descuento': obj.descuento,
'importe': round(pf * cant, DECIMALES),
'taxes': _get_taxes_product(obj.id),
}
products[obj.id] = p
vu = round(row[2], 2)
descuento = round(row[3], 2)
cant = round(row[4], 2)
pf = vu - descuento
p = {
'id_product': obj.id,
'delete': '-',
'clave': obj.clave,
'descripcion': obj.descripcion,
'unidad': obj.unidad.id,
'cantidad': cant,
'valor_unitario': vu,
'descuento': descuento,
'importe': round(pf * cant, DECIMALES),
'taxes': _get_taxes_product(obj.id),
}
products.append(p)
except Productos.DoesNotExist:
pass
log.info('Factura importada...')
return {'ok': True, 'rows': tuple(products.values())}
return {'ok': True, 'rows': tuple(products)}
def get_doc(type_doc, id, rfc):
@ -246,6 +233,7 @@ def config_timbrar():
'cfdi_tax_locales': Configuracion.get_bool('chk_config_tax_locales'),
'cfdi_tax_decimals': Configuracion.get_bool('chk_config_tax_decimals'),
'cfdi_with_taxes': Configuracion.get_bool('chk_config_price_with_taxes_in_invoice'),
'cfdi_add_same_product': Configuracion.get_bool('chk_config_add_same_product'),
}
return conf
@ -333,6 +321,7 @@ class Configuracion(BaseModel):
'chk_config_tax_locales',
'chk_config_tax_decimals',
'chk_config_price_with_taxes_in_invoice',
'chk_config_add_same_product',
'chk_config_anticipo',
'chk_config_cuenta_predial',
'chk_config_codigo_barras',
@ -2748,11 +2737,11 @@ class Productos(BaseModel):
clave = values.get('key', '')
row = (Productos
.select(
Productos.id,
Productos.id.alias('id_product'),
Productos.clave,
Productos.clave_sat,
Productos.descripcion,
SATUnidades.name.alias('unidad'),
SATUnidades.id.alias('unidad'),
Productos.valor_unitario,
Productos.descuento)
.join(SATUnidades).switch(Productos)
@ -2761,7 +2750,7 @@ class Productos(BaseModel):
.dicts()
)
if len(row):
id = row[0]['id']
id = row[0]['id_product']
model_pt = Productos.impuestos.get_through_model()
taxes = tuple(model_pt
.select(
@ -3360,7 +3349,7 @@ class Facturas(BaseModel):
}
options = {
'para': obj.cliente.correo_facturas,
'copia': values['correo_copia'],
'copia': values.get('correo_copia', ''),
'confirmar': util.get_bool(values.get('correo_confirmacion', '0')),
'asunto': util.make_info_mail(values['correo_asunto'], fields),
'mensaje': util.make_info_mail(values['correo_mensaje'], fields),
@ -3567,12 +3556,11 @@ class Facturas(BaseModel):
locales_retenciones = 0
for product in products:
# ~ print ('\n', product['descripcion'])
id_product = product.pop('id')
id_product = product.pop('id_product')
id_student = product.pop('id_student', 0)
p = Productos.get(Productos.id==id_product)
product['unidad'] = p.unidad.key
product['unidad'] = SATUnidades.get(SATUnidades.id==product['unidad']).key
product['clave'] = p.clave
product['clave_sat'] = p.clave_sat
product['cuenta_predial'] = p.cuenta_predial
@ -3793,8 +3781,8 @@ class Facturas(BaseModel):
'ClaveProdServ': row.producto.clave_sat,
'NoIdentificacion': row.producto.clave,
'Cantidad': FORMAT.format(row.cantidad),
'ClaveUnidad': row.producto.unidad.key,
'Unidad': row.producto.unidad.name[:20],
'ClaveUnidad': row.unidad,
'Unidad': SATUnidades.get(SATUnidades.key==row.unidad).name[:20],
'Descripcion': row.descripcion,
'ValorUnitario': FORMAT.format(row.valor_unitario),
'Importe': FORMAT.format(row.importe),
@ -4467,10 +4455,10 @@ class PreFacturas(BaseModel):
locales_retenciones = 0
for product in products:
id_product = product.pop('id')
id_product = product.pop('id_product')
p = Productos.get(Productos.id==id_product)
product['unidad'] = p.unidad.key
product['unidad'] = SATUnidades.get(SATUnidades.id==product['unidad']).key
product['clave'] = p.clave
product['clave_sat'] = p.clave_sat
product['cuenta_predial'] = p.cuenta_predial
@ -4717,16 +4705,16 @@ class PreFacturasDetalle(BaseModel):
PreFacturasDetalle.factura==id)
for p in reversed(productos):
row = {'id': p.producto.id}
row = {'id_product': p.producto.id}
row['clave'] = p.producto.clave
row['descripcion'] = p.descripcion
row['unidad'] = p.producto.unidad.name
row['unidad'] = p.producto.unidad.id
row['cantidad'] = p.cantidad
row['valor_unitario'] = p.valor_unitario
row['descuento'] = p.descuento
pf = p.valor_unitario - p.descuento
row['importe'] = round(pf * p.cantidad, DECIMALES)
impuestos = cls._get_impuestos(cls, row['id'])
impuestos = cls._get_impuestos(cls, row['id_product'])
data.append({'row': row, 'taxes': impuestos})
return {'rows': data, 'receptor': receptor}

View File

@ -63,6 +63,7 @@ var controllers = {
$$('chk_config_tax_locales').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_tax_decimals').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_price_with_taxes_in_invoice').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_add_same_product').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_anticipo').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_edu').attachEvent('onItemClick', chk_config_item_click)

View File

@ -167,6 +167,7 @@ function default_config(){
cfg_invoice['tax_locales'] = values.cfdi_tax_locales
cfg_invoice['tax_decimals'] = values.cfdi_tax_decimals
cfg_invoice['with_taxes'] = values.cfdi_with_taxes
cfg_invoice['add_same_product'] = values.cfdi_add_same_product
if(values.cfdi_show_pedimento){
$$('grid_details').showColumn('pedimento')
}
@ -558,10 +559,11 @@ function guardar_y_timbrar(values){
var rows = grid.data.getRange()
for (i = 0; i < rows.length; i++) {
delete rows[i]['id']
delete rows[i]['delete']
delete rows[i]['clave']
delete rows[i]['clave_sat']
delete rows[i]['unidad']
//~ delete rows[i]['unidad']
delete rows[i]['importe']
delete rows[i]['student']
rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario'])
@ -808,7 +810,7 @@ function calcular_impuestos(){
var import2 = (valor_unitario * cantidad).round(DECIMALES)
var importe = parseFloat(product.importe)
subtotal += importe
query = table_pt.chain().find({'product': product.id}).data()
query = table_pt.chain().find({'product': product.id_product}).data()
for(var tax of query){
impuesto = table_taxes.findOne({'id': tax.tax})
if(impuesto.tipo == 'E'){
@ -867,7 +869,16 @@ function set_product(values){
var taxes = values.taxes
var values = values.row
var form = $$('form_invoice')
var row = grid.getItem(values.id)
var row = undefined
if(!cfg_invoice['add_same_product']){
for(var id in grid.data.pull){
if(grid.getItem(id).id_product == values.id_product){
row = grid.getItem(id)
break
}
}
}
values['delete'] = '-'
if (row == undefined){
@ -946,7 +957,7 @@ function search_product_id_key_press(code, e){
function grid_details_before_edit_start(id){
var columns = ['', 'descripcion', 'pedimento','cantidad', 'valor_unitario', 'descuento']
var columns = ['', 'unidad', 'descripcion', 'pedimento','cantidad', 'valor_unitario', 'descuento']
if(!columns.indexOf(id.column)){
return !this.getItem(id.row)[id.column]
}
@ -956,6 +967,10 @@ function grid_details_before_edit_start(id){
function grid_details_before_edit_stop(state, editor){
var row = grid.getItem(editor.row)
if(editor.column == 'unidad'){
return true
}
if(editor.column == 'descripcion'){
if(!state.value.trim()){
msg = 'La descripción no puede estar vacía'
@ -1358,9 +1373,9 @@ function cmd_prefactura_click(){
var rows = grid.data.getRange()
for (i = 0; i < rows.length; i++) {
delete rows[i]['id']
delete rows[i]['delete']
delete rows[i]['clave']
delete rows[i]['unidad']
delete rows[i]['importe']
rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario'])
rows[i]['descuento'] = parseFloat(rows[i]['descuento'])

View File

@ -599,6 +599,8 @@ var options_admin_otros = [
labelRight: 'Calcular impuestos con 4 decimales'},
{view: 'checkbox', id: 'chk_config_price_with_taxes_in_invoice', labelWidth: 0,
labelRight: 'Precio incluye impuestos'},
{view: 'checkbox', id: 'chk_config_add_same_product', labelWidth: 0,
labelRight: 'Permitir agregar el mismo producto'},
]},
{maxHeight: 20},
{template: 'Ayudas varias', type: 'section'},

View File

@ -277,7 +277,7 @@ var grid_invoices = {
var grid_details_cols = [
{id: "id", header:"ID", hidden: true},
{id: 'id_product', header: 'id_product', hidden: true},
{id: 'delete', header: '', width: 30, css: 'delete'},
{id: "clave", header:{text: 'Clave', css: 'center'}, width: 100,
adjust: 'data'},
@ -287,7 +287,8 @@ var grid_details_cols = [
{id: "pedimento", header: 'Pedimento', editor: 'text', hidden: true},
{id: "id_student", header: 'ID_Alumno', hidden: true},
{id: 'student', header: 'Alumno', hidden: true, width: 150},
{id: "unidad", header:{text: 'Unidad', css: 'center'}, width: 100},
{id: "unidad", header:{text: 'Unidad', css: 'center'}, width: 100,
editor: 'select', options: 'values/unidades'},
{id: 'cantidad', header: {text: 'Cantidad', css: 'center'}, width: 100,
format: webix.i18n.numberFormat, css: 'right', editor: 'text'},
{id: "valor_unitario", header:{text: 'Valor Unitario', css: 'center'},