Agregar cancelación con certificados con el pac CD

This commit is contained in:
El Mau 2021-11-26 13:14:43 -06:00
parent e372f064b4
commit 28ef107949
10 changed files with 148 additions and 45 deletions

View File

@ -725,6 +725,12 @@ class AppWareHouseProduct(object):
req.context['result'] = self._db.warehouseproduct_get(values)
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):

View File

@ -173,8 +173,6 @@ class SATCertificate(object):
tree, encoding='utf-8', xml_declaration=True).decode()
# ~ xml_signed = xml_signed.replace("'", '"').replace('utf', 'UTF')
print(xml_signed)
return xml_signed
@property

View File

@ -17,6 +17,7 @@
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
import logging
import lxml.etree as ET
@ -146,6 +147,11 @@ class PACComercioDigital(object):
return data
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 = {
'cfdi': 'http://www.sat.gob.mx/cfd/3',
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
@ -200,7 +206,15 @@ class PACComercioDigital(object):
self._error(result.headers['errmsg'])
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):
NS_CFDI = {

View File

@ -16,7 +16,7 @@
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
# ~ import base64
import datetime
import logging
import os
@ -129,7 +129,9 @@ class PACFinkok(object):
return {}
if self.CODE['200'] != ce:
log.error('CodEstatus', type(ce), ce)
self._error = ce
return {}
return result
return result
@ -243,8 +245,6 @@ class PACFinkok(object):
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
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 = {
'xml': xml.encode(),
'username': auth['user'],

View File

@ -665,7 +665,7 @@ def get_pac_by_rfc(cfdi):
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())
pac = PACS[auth['pac']]()
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):
if auth['pac'] == 'finkok':
return _cancel_finkok(invoice, auth, certificado)
# ~ if auth['pac'] == 'finkok':
# ~ return _cancel_finkok(invoice, auth, certificado)
return _cancel_with_cert(invoice, auth, certificado)
cert = SATCertificate(certificado.cer, certificado.key_enc.encode())
pac = PACS[auth['pac']]()
@ -695,6 +696,7 @@ def cancel_xml_sign(invoice, auth, certificado):
template = TEMPLATE_CANCEL.format(**data)
tree = ET.fromstring(template.encode())
sign_xml = cert.sign_xml(tree)
result = pac.cancel_xml(sign_xml, auth, invoice.xml)
if pac.error:

View File

@ -496,6 +496,9 @@ class StorageEngine(object):
def warehouseproduct_get(self, 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):
return main.Usuarios.get_data(filters, user)

View File

@ -4088,6 +4088,39 @@ class WareHouseProduct(BaseModel):
obj.save()
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):
producto = ForeignKeyField(Productos)
@ -4221,10 +4254,6 @@ class Facturas(BaseModel):
msg = 'No es posible cancelar CFDI 3.2'
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)
if data['ok']:
@ -9915,8 +9944,6 @@ class InventoryEntries(BaseModel):
result = {'ok': False, 'msg': msg}
return result
print(0, args)
storage = args['target']
cant = Decimal(args['cant'])
values = dict(

View File

@ -250,35 +250,6 @@ DEFAULT_GLOBAL = {
'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}">
<Folios>
<UUID>{uuid}</UUID>

View File

@ -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)
}
}
})
}

View File

@ -502,6 +502,13 @@ var body_win_show_exists = {rows: [{maxHeight: 10, minHeight: 10},
labelPosition: 'top', required: false, options: []}, {maxWidth: 10},
{view: 'button', id: 'cmd_warehouse_move', label: 'Mover', maxWidth: 100},
{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},
{cols: [{},
{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_warehouse_move').attachEvent('onItemClick', cmd_warehouse_move_click)
$$('cmd_adjust_stock').attachEvent('onItemClick', cmd_adjust_stock_click)
}
}