import os
from ctypes import *

cCurDir = os.path.dirname(os.path.abspath(__file__))+"\\" # devuelve la ruta del archivo .py actual

# Cargar la DLL y crear sus wrappers
vxml = cdll.LoadLibrary(cCurDir+"VXML_x64.dll")
vxml.VXML_NewW.restype = c_void_p
vxml.VXML_NewW.argtypes = [c_wchar_p]
vxml.VXML_NewWithLogW.restype = c_void_p
vxml.VXML_NewWithLogW.argtypes = [c_wchar_p, c_wchar_p]
vxml.VXML_SetUserInfoW.argtypes = [c_void_p,c_wchar_p, c_wchar_p]
vxml.VXML_AddCfdiRelacionados_cfdi40W.argtypes = [c_void_p,c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_AddCfdiRelacionado_cfdi40W.argtypes = [c_void_p,c_wchar_p]
vxml.VXML_SetComprobanteInfo_cfdi40W.argtypes = [c_void_p,c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_SetEmisorInfo_cfdi40W.argtypes = [c_void_p,c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_SetReceptorInfo_cfdi40W.argtypes = [c_void_p,c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_AddConcepto_cfdi40W.argtypes = [c_void_p,c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_AddConceptoTraslado_cfdi40W.argtypes = [c_void_p,c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]           
vxml.VXML_SetImpuestosInfo_cfdi40W.argtypes = [c_void_p,c_wchar_p, c_wchar_p]       
vxml.VXML_AddTraslado_cfdi40W.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_ProcesaDocumentoW.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_GetValueW.argtypes = [c_void_p, c_int]
vxml.VXML_GetValueW.restype = c_wchar_p
vxml.VXML_FreeW.argtypes = [c_void_p]
vxml.VXML_SetPagos20W.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_Pagos20AddPagoW.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_Pagos20AddPagoDoctoRelacionadoW.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_Pagos20AddPagoDoctoRelacionadoTrasladoDRW.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_Pagos20AddPagoImpuestosPTrasladoPW.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]
vxml.VXML_Pagos20AddPagoImpuestosPRetencionPW.argtypes = [c_void_p, c_wchar_p, c_wchar_p]
vxml.VXML_Pagos20AddPagoDoctoRelacionadoRetencionDRW.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p, c_wchar_p]

print(">>>>>>>>>>> Timbrado CFDI 4.0 con complmento Pagos 2.0")

hXml = vxml.VXML_NewWithLogW("4.0",cCurDir+"CFDI40_Demo_Pagos20.log")

vxml.VXML_SetUserInfoW(hXml,"demo_cibertec","demo")
vxml.VXML_SetComprobanteInfo_cfdi40W(hXml,"","12629","%cb_date","","","0","","XXX","","0","P","","72150","","01")
vxml.VXML_SetEmisorInfo_cfdi40W(hXml,"EKU9003173C9","ESCUELA KEMPER URGATE","601","")
vxml.VXML_SetReceptorInfo_cfdi40W(hXml,"CTE940531F58","CIBERNETICA Y TECNOLOGIA","","","CP01","53050","601")
vxml.VXML_AddConcepto_cfdi40W(hXml,"84111506","","1","ACT","","Pago","0","0","","01")

# Complemento de pagos 2.0 

# Antes de empezar con el complemento debemos tener todos los importes calculados previamente
vxml.VXML_SetPagos20W(hXml,"4930.51","4622.37","","64844.45","10375.12","","","","","","65666.67")

# Ejemplo 1. Pago parcial de una factura
#
#     Importe total de la factura original: $15,000.00
#                 Importe del pago parcial: $10,000.00 IVA INCLUIDO
#               Importe del saldo insoluto: $ 5,000.00
vxml.VXML_Pagos20AddPagoW(hXml,"2025-01-10T01:01:01","03","MXN","1","10000.00","0000842","","","","","","","","","")
# agregamos un documento relacionado 
vxml.VXML_Pagos20AddPagoDoctoRelacionadoW(hXml,"8ADC78F8-4444-4444-4444-121212121212","Serie","0001","MXN","1","1","15000.00","10000.00","5000.00","02")
# desglose de impuestos del documento relacionado
#  Importe del pago: $10,000 IVA incluido
# Desglose de Impuestos:
#              Base de calculo del IVA: $ 8,620.69 (10,000 / 1.16)
#                        IVA aplicable: $ 1,379.31 (10,000 - 8,620.69) 
vxml.VXML_Pagos20AddPagoDoctoRelacionadoTrasladoDRW(hXml,"8620.69","002","Tasa","0.160000","1379.31")
# resumen de impuestos de todos los documentos relacionados 
vxml.VXML_Pagos20AddPagoImpuestosPTrasladoPW(hXml,"8620.69","002","Tasa","0.160000","1379.31")

# Ejemplo 2. Pago total de una factura 
#
#  Importe total de la factura original: $11,600.00
#                      Importe del pago: $11,600.00 IVA Incluido
#            Importe del saldo insoluto: $0.00
vxml.VXML_Pagos20AddPagoW(hXml,"2025-01-01T10:01:01","03","MXN","1","11600.00","0000843","","","","","","","","","")
vxml.VXML_Pagos20AddPagoDoctoRelacionadoW(hXml,"8ADC78F8-4AB4-44FC-34AD-121212121212","Serie","00002","MXN","1","1","11600.00","11600.00","0.00","02")
#  desglose de impuestos del documento relacionado
#      Importe del pago: $11,600.00 IVA incluido
#        Desglose de impuestos:
#                Base de calculo del IVA: $10,000.00 (11,600 / 1.16)
#                          IVA aplicable: $ 1,600.00 (11,600 - 10,000)
vxml.VXML_Pagos20AddPagoDoctoRelacionadoTrasladoDRW(hXml,"10000.00","002","Tasa","0.160000","1600.00")
vxml.VXML_Pagos20AddPagoImpuestosPTrasladoPW(hXml,"10000.00","002","Tasa","0.160000","1600.00")

# Ejempmlo 3. Pago Total de una factura con impuestos retenidos, el calculo es mas complejo y se complica mas aún si es un pago parcial. En este caso es un pago total
#     Importe total de la factura original: $ 19,066.67
#                         Importe del pago: $ 19,066.67 IVA y retenciones incluidas
#               Importe del saldo insoluto: $0.00 
vxml.VXML_Pagos20AddPagoW(hXml,"2025-01-01T10:01:01","03","MXN","1","19066.67","0000844","","","","","","","","","")
vxml.VXML_Pagos20AddPagoDoctoRelacionadoW(hXml,"F1DC78F8-4AB4-44FC-35AF-121212121212","Serie","00003","MXN","1","1","19066.67","19066.67","0.00","02")
# desglose de los impuestos TRASLADADOS:
#     Desglose de impuestos:
#             Base de calculo del IVA: $20,000.00
#                       IVA aplicable: $ 3,200.00 
vxml.VXML_Pagos20AddPagoDoctoRelacionadoTrasladoDRW(hXml,"20000.00","002","Tasa","0.160000","3200.00")
#  desglose de los impuestos RETENIDOS
#     Desglose de impuestos:
#               Base para la retencion de impuestos: $20,000.00
#                          Retencion del 10% de ISR: $ 2,000.00
#                   Retencion de 2/3 partes del IVA: $ 2,133.32  (20,000 * 10.6666...%)
vxml.VXML_Pagos20AddPagoDoctoRelacionadoRetencionDRW(hXml,"20000.00","001","Tasa","0.100000","2000.00")
vxml.VXML_Pagos20AddPagoDoctoRelacionadoRetencionDRW(hXml,"20000.00","002","Tasa","0.106666","2133.32")
vxml.VXML_Pagos20AddPagoImpuestosPTrasladoPW(hXml,"20000.00","002","Tasa","0.160000","3200.00")
vxml.VXML_Pagos20AddPagoImpuestosPRetencionPW(hXml,"001","2000.00")
vxml.VXML_Pagos20AddPagoImpuestosPRetencionPW(hXml,"002","2133.32")

# Ejemplo 4. Pago parcial de la factura con impuestos retenidos, este ejemplo es el mas complejo del complemento de pagos, porque hay que calcular porcentajes sobre los montos
#            al aumentar el numero de decimales por culpa de los porcentajes, los calculos se vuelven imprecisos al realizar el redondeo, buena suerte en tus calculos
#
#     La factura original esta calculada de la siguiente manera:
#
#                    Importe de la factura original: $40,000.00
#                            + IVA Factura original: $ 6,400.00
#                            - Retencion 10% de ISR: $ 4,000.00
#                    - Retencion 2/3 partes del IVA: $ 4,266.67
#                                             TOTAL: $38,133.33 <---- sobre este importe trabajaremos
#
#     Importe total de la factura original: $ 38,133.33
#                         Importe del pago: $ 25,000.00 IVA y retenciones incluidas
#               Importe del saldo insoluto: $ 13,133.33
#
#  Hasta aqui la parte fácil 
vxml.VXML_Pagos20AddPagoW(hXml,"2025-01-01T10:01:01","03","MXN","1","25000.00","0000845","","","","","","","","","")
vxml.VXML_Pagos20AddPagoDoctoRelacionadoW(hXml,"F1DC78F8-4AB4-44FC-35AF-121212121212","Serie","00003","MXN","1","1","38133.33","25000.00","13133.33","02")
#  Desglose de los impuestos TRASLADADOS, para definir el importe debemos calcular el % que el pago realizado representa sobre el total y aplicar dicho % a todos los montos: iva trasladado, retenido y el isr
#     Asi que aplicacamos una regla de 3 simple:
#
#     $38,133.33 - 100% de la factura
#     $25,000.00 - ???% de la factura ---> 65.5594% <-- este porcentaje aplicaremos sobre todas las operaciones
#
#     Desglose de impuestos:
#                Base de calculo del IVA: $26,223.76 ($40,000.00, importe de la factura original antes de impuestos * 0.65594)
#                         IVA aplicable: $ 4,195.81 ($26,223.76 * 16%) 
vxml.VXML_Pagos20AddPagoDoctoRelacionadoTrasladoDRW(hXml,"26223.76","002","Tasa","0.160000","4195.81")
# Desglose de los impuestos RETENIDOS
#      Desglose de impuestos:
#                 Base para la retencion de impuestos: $26,223.76
#                            Retencion del 10% de ISR: $ 2,622.37
#                     Retencion de 2/3 partes del IVA: $ 2,797.19  ($4,195.81 * 10.6666...%)
vxml.VXML_Pagos20AddPagoDoctoRelacionadoRetencionDRW(hXml,"26223.76","001","Tasa","0.100000","2622.37")
vxml.VXML_Pagos20AddPagoDoctoRelacionadoRetencionDRW(hXml,"26223.76","002","Tasa","0.106666","2797.19")
vxml.VXML_Pagos20AddPagoImpuestosPTrasladoPW(hXml,"26223.76","002","Tasa","0.160000","4195.81")
vxml.VXML_Pagos20AddPagoImpuestosPRetencionPW(hXml,"001","2622.37")
vxml.VXML_Pagos20AddPagoImpuestosPRetencionPW(hXml,"002","2797.19")

 # generamos el CFDI
nResultado = vxml.VXML_ProcesaDocumentoW(
    hXml, cCurDir+"CSD_EKU9003173C9.cer", cCurDir+"CSD_EKU9003173C9.key", "12345678a", cCurDir+"CFDI40_Demo_Pagos20.xml")

if (nResultado == 0):
    for i in range(1, 22):
        value_wide = c_wchar_p(vxml.VXML_GetValueW(hXml, i))
        print("GetValue [" + str(i).zfill(2) + "] = " + value_wide.value)
else:
    value1_wide = c_wchar_p(vxml.VXML_GetValueW(hXml, 1))
    value2_wide = c_wchar_p(vxml.VXML_GetValueW(hXml, 2))
    print("Error en el CFDI [" + value1_wide.value +
          "] = " + value2_wide.value)

vxml.VXML_FreeW(hXml)

print(">>>>>>>>>>> Finished!")