forked from elmau/empresa-libre
Agregar cancelación con certificados con el pac CD
This commit is contained in:
parent
e372f064b4
commit
28ef107949
|
@ -725,6 +725,12 @@ class AppWareHouseProduct(object):
|
||||||
req.context['result'] = self._db.warehouseproduct_get(values)
|
req.context['result'] = self._db.warehouseproduct_get(values)
|
||||||
resp.status = falcon.HTTP_200
|
resp.status = falcon.HTTP_200
|
||||||
|
|
||||||
|
def on_post(self, req, resp):
|
||||||
|
values = req.params
|
||||||
|
user = req.env['beaker.session']['userobj']
|
||||||
|
req.context['result'] = self._db.warehouseproduct_post(values, user)
|
||||||
|
resp.status = falcon.HTTP_200
|
||||||
|
|
||||||
|
|
||||||
class AppTicketsDetails(object):
|
class AppTicketsDetails(object):
|
||||||
|
|
||||||
|
|
|
@ -173,8 +173,6 @@ class SATCertificate(object):
|
||||||
tree, encoding='utf-8', xml_declaration=True).decode()
|
tree, encoding='utf-8', xml_declaration=True).decode()
|
||||||
# ~ xml_signed = xml_signed.replace("'", '"').replace('utf', 'UTF')
|
# ~ xml_signed = xml_signed.replace("'", '"').replace('utf', 'UTF')
|
||||||
|
|
||||||
print(xml_signed)
|
|
||||||
|
|
||||||
return xml_signed
|
return xml_signed
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
import base64
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import lxml.etree as ET
|
import lxml.etree as ET
|
||||||
|
@ -146,6 +147,11 @@ class PACComercioDigital(object):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _get_data_cancel(self, cfdi, info, auth):
|
def _get_data_cancel(self, cfdi, info, auth):
|
||||||
|
info['pass'] = '12345678a'
|
||||||
|
info['tipo'] = 'cfdi3.3'
|
||||||
|
info['key'] = base64.b64encode(info['key']).decode()
|
||||||
|
info['cer'] = base64.b64encode(info['cer']).decode()
|
||||||
|
|
||||||
NS_CFDI = {
|
NS_CFDI = {
|
||||||
'cfdi': 'http://www.sat.gob.mx/cfd/3',
|
'cfdi': 'http://www.sat.gob.mx/cfd/3',
|
||||||
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
|
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
|
||||||
|
@ -200,7 +206,15 @@ class PACComercioDigital(object):
|
||||||
self._error(result.headers['errmsg'])
|
self._error(result.headers['errmsg'])
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
return result.text
|
tree = ET.fromstring(result.text)
|
||||||
|
date_cancel = tree.xpath('string(//Acuse/@Fecha)')[:19]
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'acuse': result.text,
|
||||||
|
'date': date_cancel,
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
def _get_headers_cancel_xml(self, cfdi, info, auth):
|
def _get_headers_cancel_xml(self, cfdi, info, auth):
|
||||||
NS_CFDI = {
|
NS_CFDI = {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
# ~ You should have received a copy of the GNU General Public License
|
# ~ You should have received a copy of the GNU General Public License
|
||||||
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import base64
|
# ~ import base64
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -129,7 +129,9 @@ class PACFinkok(object):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
if self.CODE['200'] != ce:
|
if self.CODE['200'] != ce:
|
||||||
log.error('CodEstatus', type(ce), ce)
|
self._error = ce
|
||||||
|
return {}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -243,8 +245,6 @@ class PACFinkok(object):
|
||||||
client = Client(self.URL[method],
|
client = Client(self.URL[method],
|
||||||
transport=self._transport, plugins=self._plugins)
|
transport=self._transport, plugins=self._plugins)
|
||||||
client.set_ns_prefix('can', 'http://facturacion.finkok.com/cancel')
|
client.set_ns_prefix('can', 'http://facturacion.finkok.com/cancel')
|
||||||
# ~ xml = f'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n{xml}'
|
|
||||||
# ~ xml = f'<?xml version="1.0" encoding="UTF-8" standalone="true"?>\n{xml}'
|
|
||||||
args = {
|
args = {
|
||||||
'xml': xml.encode(),
|
'xml': xml.encode(),
|
||||||
'username': auth['user'],
|
'username': auth['user'],
|
||||||
|
|
|
@ -665,7 +665,7 @@ def get_pac_by_rfc(cfdi):
|
||||||
return RFCS[rfc_pac]
|
return RFCS[rfc_pac]
|
||||||
|
|
||||||
|
|
||||||
def _cancel_finkok(invoice, auth, certificado):
|
def _cancel_with_cert(invoice, auth, certificado):
|
||||||
cert = SATCertificate(certificado.cer, certificado.key_enc.encode())
|
cert = SATCertificate(certificado.cer, certificado.key_enc.encode())
|
||||||
pac = PACS[auth['pac']]()
|
pac = PACS[auth['pac']]()
|
||||||
info = {'cer': cert.cer_pem, 'key': cert.key_pem}
|
info = {'cer': cert.cer_pem, 'key': cert.key_pem}
|
||||||
|
@ -682,8 +682,9 @@ def _cancel_finkok(invoice, auth, certificado):
|
||||||
|
|
||||||
|
|
||||||
def cancel_xml_sign(invoice, auth, certificado):
|
def cancel_xml_sign(invoice, auth, certificado):
|
||||||
if auth['pac'] == 'finkok':
|
# ~ if auth['pac'] == 'finkok':
|
||||||
return _cancel_finkok(invoice, auth, certificado)
|
# ~ return _cancel_finkok(invoice, auth, certificado)
|
||||||
|
return _cancel_with_cert(invoice, auth, certificado)
|
||||||
|
|
||||||
cert = SATCertificate(certificado.cer, certificado.key_enc.encode())
|
cert = SATCertificate(certificado.cer, certificado.key_enc.encode())
|
||||||
pac = PACS[auth['pac']]()
|
pac = PACS[auth['pac']]()
|
||||||
|
@ -695,6 +696,7 @@ def cancel_xml_sign(invoice, auth, certificado):
|
||||||
template = TEMPLATE_CANCEL.format(**data)
|
template = TEMPLATE_CANCEL.format(**data)
|
||||||
tree = ET.fromstring(template.encode())
|
tree = ET.fromstring(template.encode())
|
||||||
sign_xml = cert.sign_xml(tree)
|
sign_xml = cert.sign_xml(tree)
|
||||||
|
|
||||||
result = pac.cancel_xml(sign_xml, auth, invoice.xml)
|
result = pac.cancel_xml(sign_xml, auth, invoice.xml)
|
||||||
|
|
||||||
if pac.error:
|
if pac.error:
|
||||||
|
|
|
@ -496,6 +496,9 @@ class StorageEngine(object):
|
||||||
def warehouseproduct_get(self, filters):
|
def warehouseproduct_get(self, filters):
|
||||||
return main.WareHouseProduct.get_data(filters)
|
return main.WareHouseProduct.get_data(filters)
|
||||||
|
|
||||||
|
def warehouseproduct_post(self, filters, user):
|
||||||
|
return main.WareHouseProduct.post(filters, user)
|
||||||
|
|
||||||
def users_get(self, filters, user):
|
def users_get(self, filters, user):
|
||||||
return main.Usuarios.get_data(filters, user)
|
return main.Usuarios.get_data(filters, user)
|
||||||
|
|
||||||
|
|
|
@ -4088,6 +4088,39 @@ class WareHouseProduct(BaseModel):
|
||||||
obj.save()
|
obj.save()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _adjust_stock(cls, args, user):
|
||||||
|
cant = args['cant']
|
||||||
|
fields = dict(
|
||||||
|
warehouse = args['storage'],
|
||||||
|
product = args['id_product'],
|
||||||
|
)
|
||||||
|
obj = WareHouseProduct.get(**fields)
|
||||||
|
obj.exists += cant
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
total = (WareHouseProduct
|
||||||
|
.select(fn.Sum(WareHouseProduct.exists)).alias('total')
|
||||||
|
.where(WareHouseProduct.product==fields['product'])
|
||||||
|
.limit(1)
|
||||||
|
.scalar()
|
||||||
|
)
|
||||||
|
query = (Productos
|
||||||
|
.update(existencia=total)
|
||||||
|
.where(Productos.id==fields['product'])
|
||||||
|
)
|
||||||
|
query.execute()
|
||||||
|
|
||||||
|
result = {'ok': True, 'row': {'existencia': total}}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def post(cls, values, user):
|
||||||
|
opt = values['opt']
|
||||||
|
args = utils.loads(values['values'])
|
||||||
|
return getattr(cls, f'_{opt}')(args, user)
|
||||||
|
|
||||||
|
|
||||||
class RangosPrecios(BaseModel):
|
class RangosPrecios(BaseModel):
|
||||||
producto = ForeignKeyField(Productos)
|
producto = ForeignKeyField(Productos)
|
||||||
|
@ -4221,10 +4254,6 @@ class Facturas(BaseModel):
|
||||||
msg = 'No es posible cancelar CFDI 3.2'
|
msg = 'No es posible cancelar CFDI 3.2'
|
||||||
return {'ok': False, 'msg': msg}
|
return {'ok': False, 'msg': msg}
|
||||||
|
|
||||||
# ~ pac = Configuracion.get_('lst_pac').lower()
|
|
||||||
# ~ if pac:
|
|
||||||
# ~ data, result = utils.xml_cancel(obj.xml, auth, certificado, pac)
|
|
||||||
# ~ else:
|
|
||||||
data, result = util.cancel_xml(auth, obj.uuid, certificado)
|
data, result = util.cancel_xml(auth, obj.uuid, certificado)
|
||||||
|
|
||||||
if data['ok']:
|
if data['ok']:
|
||||||
|
@ -9915,8 +9944,6 @@ class InventoryEntries(BaseModel):
|
||||||
result = {'ok': False, 'msg': msg}
|
result = {'ok': False, 'msg': msg}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
print(0, args)
|
|
||||||
|
|
||||||
storage = args['target']
|
storage = args['target']
|
||||||
cant = Decimal(args['cant'])
|
cant = Decimal(args['cant'])
|
||||||
values = dict(
|
values = dict(
|
||||||
|
|
|
@ -250,35 +250,6 @@ DEFAULT_GLOBAL = {
|
||||||
'clave_sat': '01010101',
|
'clave_sat': '01010101',
|
||||||
}
|
}
|
||||||
|
|
||||||
# ~ TEMPLATE_CANCEL = """<Cancelacion RfcEmisor="{rfc}" Fecha="{fecha}" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://cancelacfd.sat.gob.mx">
|
|
||||||
# ~ <Folios>
|
|
||||||
# ~ <UUID>{uuid}</UUID>
|
|
||||||
# ~ </Folios>
|
|
||||||
# ~ <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
||||||
# ~ <SignedInfo>
|
|
||||||
# ~ <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
|
|
||||||
# ~ <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
|
|
||||||
# ~ <Reference URI="">
|
|
||||||
# ~ <Transforms>
|
|
||||||
# ~ <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
|
|
||||||
# ~ </Transforms>
|
|
||||||
# ~ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
|
|
||||||
# ~ <DigestValue />
|
|
||||||
# ~ </Reference>
|
|
||||||
# ~ </SignedInfo>
|
|
||||||
# ~ <SignatureValue />
|
|
||||||
# ~ <KeyInfo>
|
|
||||||
# ~ <X509Data>
|
|
||||||
# ~ <X509SubjectName />
|
|
||||||
# ~ <X509IssuerSerial />
|
|
||||||
# ~ <X509Certificate />
|
|
||||||
# ~ </X509Data>
|
|
||||||
# ~ <KeyValue />
|
|
||||||
# ~ </KeyInfo>
|
|
||||||
# ~ </Signature>
|
|
||||||
# ~ </Cancelacion>
|
|
||||||
# ~ """
|
|
||||||
|
|
||||||
TEMPLATE_CANCEL = """<Cancelacion xmlns="http://cancelacfd.sat.gob.mx" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Fecha="{fecha}" RfcEmisor="{rfc}">
|
TEMPLATE_CANCEL = """<Cancelacion xmlns="http://cancelacfd.sat.gob.mx" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Fecha="{fecha}" RfcEmisor="{rfc}">
|
||||||
<Folios>
|
<Folios>
|
||||||
<UUID>{uuid}</UUID>
|
<UUID>{uuid}</UUID>
|
||||||
|
|
|
@ -910,3 +910,77 @@ function _add_entries_inventory_manual(row_id, data){
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function cmd_adjust_stock_click(id, e, node){
|
||||||
|
var id_product = $$('txt_id_product').getValue()
|
||||||
|
var row = $$('grid_warehouse_exists').getSelectedItem()
|
||||||
|
if (row == undefined){
|
||||||
|
msg_error('Selecciona un Almacen origen')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var warehouse_source = row.id
|
||||||
|
var cant_to_adjust = $$('txt_cant_to_adjust').getValue()
|
||||||
|
|
||||||
|
if(cant_to_adjust == 0){
|
||||||
|
msg_error('La cantidad a ajustar no puede ser cero')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cant_to_adjust > row.exists){
|
||||||
|
msg_error('La cantidad a ajustar no puede ser mayor a la existencia')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = {
|
||||||
|
id_product: id_product,
|
||||||
|
cant: cant_to_adjust,
|
||||||
|
storage: warehouse_source,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = '¿Estás seguro de hacer este ajuste?'
|
||||||
|
webix.confirm({
|
||||||
|
title: 'Ajuste de Almacen',
|
||||||
|
ok: 'Si',
|
||||||
|
cancel: 'No',
|
||||||
|
type: 'confirm-error',
|
||||||
|
text: msg,
|
||||||
|
callback:function(result){
|
||||||
|
if(result){
|
||||||
|
_adjust_stock(values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _adjust_stock(args){
|
||||||
|
var grid = $$('grid_products')
|
||||||
|
var row = grid.getSelectedItem()
|
||||||
|
|
||||||
|
var values = {
|
||||||
|
opt: 'adjust_stock',
|
||||||
|
values: args,
|
||||||
|
}
|
||||||
|
|
||||||
|
webix.ajax().sync().post('warehouseproduct', values, {
|
||||||
|
error:function(text, data, XmlHttpRequest){
|
||||||
|
msg = 'Ocurrio un error, consulta a soporte técnico'
|
||||||
|
msg_error(msg)
|
||||||
|
},
|
||||||
|
success:function(text, data, XmlHttpRequest){
|
||||||
|
var values = data.json();
|
||||||
|
if (values.ok) {
|
||||||
|
$$('txt_cant_to_adjust').setValue(0)
|
||||||
|
$$('grid_warehouse_exists').load('warehouseproduct?opt=by_product&id=' + args.id_product)
|
||||||
|
$$('grid_warehouse_exists').clearSelection()
|
||||||
|
|
||||||
|
grid.updateItem(row['id'], values.row)
|
||||||
|
grid.refresh()
|
||||||
|
|
||||||
|
msg_ok('Ajuste realizado correctamente')
|
||||||
|
}else{
|
||||||
|
msg_error(values.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -502,6 +502,13 @@ var body_win_show_exists = {rows: [{maxHeight: 10, minHeight: 10},
|
||||||
labelPosition: 'top', required: false, options: []}, {maxWidth: 10},
|
labelPosition: 'top', required: false, options: []}, {maxWidth: 10},
|
||||||
{view: 'button', id: 'cmd_warehouse_move', label: 'Mover', maxWidth: 100},
|
{view: 'button', id: 'cmd_warehouse_move', label: 'Mover', maxWidth: 100},
|
||||||
{maxWidth: 10}]},
|
{maxWidth: 10}]},
|
||||||
|
{minHeight: 25, maxHeight: 25},
|
||||||
|
{template: 'Ajuste de almacen', type: 'section'},
|
||||||
|
{cols: [{maxWidth: 10},
|
||||||
|
{view: 'counter', id: 'txt_cant_to_adjust', label: 'Cantidad a ajustar:',
|
||||||
|
labelPosition: 'top', step: 1, value: 0, min: -1000000},
|
||||||
|
{view: 'button', id: 'cmd_adjust_stock', label: 'Ajustar', maxWidth: 100},
|
||||||
|
{maxWidth: 10}]},
|
||||||
{maxHeight: 20, minHeight: 20},
|
{maxHeight: 20, minHeight: 20},
|
||||||
{cols: [{},
|
{cols: [{},
|
||||||
{view: 'button', id: 'cmd_win_show_exists_close', label: 'Cerrar', type: 'danger'},
|
{view: 'button', id: 'cmd_win_show_exists_close', label: 'Cerrar', type: 'danger'},
|
||||||
|
@ -523,5 +530,6 @@ var win_show_exists = {
|
||||||
})
|
})
|
||||||
$$('cmd_win_show_exists_close').attachEvent('onItemClick', cmd_win_show_exists_close_click)
|
$$('cmd_win_show_exists_close').attachEvent('onItemClick', cmd_win_show_exists_close_click)
|
||||||
$$('cmd_warehouse_move').attachEvent('onItemClick', cmd_warehouse_move_click)
|
$$('cmd_warehouse_move').attachEvent('onItemClick', cmd_warehouse_move_click)
|
||||||
|
$$('cmd_adjust_stock').attachEvent('onItemClick', cmd_adjust_stock_click)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue