Llevo un poco más de 20 años en la profesión contable y algo de 13 años programando en VBA de Excel. Ahora percibo a la SUNAT más cerca que nunca.
Como PRICO en Febrero, tenemos:
- Declaración Jurada Mensual con Registro de Ventas y Compras Electrónicos (Por los impuestos vencidos en Enero, aunque han aplazado para Mayo la presentación, igual ya lo hice y ya los presente.)
- DAOT
- Declaración Jurada Anual de Renta (Tengo el sano habito de presentar en Febrero, un mes antes)
- Cálculo de la repartición de utilidades
- ITF
- El día a día, los reportes a la casa matriz, la encuesta del BCR, sólo falta el MTPE y el INEI.
En fin, no es una queja, es una realidad!
Sin embargo, la SUNAT ha cursado aproximadamente a 1,500 PRICOS una carta en donde se solicita: Flujogramas, Memorias, Informes de Auditoria, Cuestionarios de Auditoria, los ahora los famosos Libros Electrónicos por el ejercicio 2011. etc. Todo ello en 30 días hábiles!!!
La presente entrada tiene como propósito (nuevamente), destacar lo importante que resulta para la profesión contable saber sobre manejo de Base de datos, Programación y Excel avanzado.
Ah! Olvidaba! Luego de 4 llamadas postergadas, la empresa Real System me ofreció actualizar el CONCAR para el 20/Febrero…mi declaración vencía el 19!
No sé en que acabo el tema, ya que tuve obtener el requerimiento de SUNAT por mi cuenta. En SUNAT nos comentaron que los fabricantes de software contable no les queda otra alternativa: Tienen que adaptarse a sus requerimientos si desean continuar operando en el mercado.
El presente caso es muy particular a la empresa en donde laboro, tal vez usted intente recrearlo y no consiga éxito, tal vez usted no tenga la configuración correcta en su sistema contable, tal vez su Registro de Ventas acumule por rangos los comprobantes (por lo que habría que variar “un poco” el código de programación que se expone), etc.
Ahí vamos…
Desde Excel abra un libro en blanco y guárdelo con el nombre de: PROGRAMA DE LIBROS ELECTRONICOS - PLE (Aplicación), por ejemplo.
Presione ALT + F11 para ejecutar el Editor de Visual Basic para Aplicaciones
Desde el editor de VB, inserte un formulario
Con el formulario seleccionado presione F4 para mostrar la ventana de propiedades y asigne a la propiedad Name el siguiente valor frm_PLE
De manera similar, asigne a la propiedad Caption el siguiente valor PROGRAMA DE LIBROS ELECTRONICOS [PLE]
Muestre el cuadro de controles y presione en Toolbar
Si no tiene el control Toolbar, agréguelo de la siguiente forma:
Botón derecho del mouse sobre cualquier control, seleccione controles adicionales
Ubique Microsoft Toolbar Control, seleccione la casilla de verificación con un aspa (x) y presione Aceptar.
Ahora, presione con el mouse el control Toolbar (desde el cuadro de controles) y arrastre el puntero dentro del formulario.
Trate que los controles queden de forma similar a la siguiente imagen:
Presione el botón derecho del Mouse sobre el control Toolbar que acaba de agregar en el formulario y seleccione propiedades.
En la ventana de propiedades asigne a la propiedad Name el siguiente valor Barra_PLE
Ahora agregue botones de menús a su barra de herramientas, presione el botón personalizado
En la ventana de propiedades seleccione la ficha Buttons y presione Insertar Botón
Asigne a la propiedad Caption el siguiente valor REGISTROS
Asigne a la propiedad Style el siguiente valor 5 - tbrDropdown
Repita la operación para el siguiente menú, Presione Insertar Botón, Asigne a la propiedad Caption el siguiente valor LIBROS y Asigne a la propiedad Style el siguiente valor 5 – tbrDropdown
Note como la propiedad Index identifica los menús.
Vuelva al índice 1, es decir al primer botón que inserto, llamado REGISTROS e inserte un submenú, Asigne a la propiedad Text el siguiente valor REGISTRO DE VENTAS... y Asigne a la propiedad Key el siguiente valor REGISTRO DE VENTAS...
Para el menú REGISTROS
Repita la operación agregando los submenús:
REGISTRO DE COMPRAS...
SALIR
Para el menú LIBROS
Repita la operación agregando los submenús:
LIBRO DIARIO...
LIBRO DIARIO FORMATO SIMPLIFICADO...
LIBRO MAYOR...
No olvide asignar la propiedad Text y la propiedad Key para cada submenú
La propiedad Key es muy importante, le va otorgar funcionamiento con código de programación.
Cuando haya terminado ejecute el formulario con el botón ejecutar o presione F5
Su formulario deberá verse similar a la siguiente imagen:
Cierre el formulario para salir de tiempo de ejecución y vuelva al editor de VB para continuar con la interfase de diseño.
La idea es crear una barra de herramientas que contenga varios submenús, cada submenú llama a un subformulario que solicita el mes y el año, datos mínimos para poder ejecutar nuestros registros y libros electrónicos, en este ejemplo el Registro de Ventas.
El subformulario deberá quedar similar a la siguiente imagen:
Para ello, desde el editor de VB, inserte un formulario y agregue los siguientes controles (trate de seguir el mismo orden)
ORDEN
|
CANTIDAD
|
CONTROL
|
PROPIEDAD
|
VALOR
|
1er
|
1
|
Userform (Formulario)
|
Name
|
frm_REG_VTA_PLE
|
1er
|
1
|
Userform (Formulario)
|
Caption
|
REGISTRO DE VENTAS [PLE]
|
1er
|
1
|
Frame (Grupo)
|
Caption
|
SELECCIONE EL PERIODO TRIBUTARIO
|
1er
|
1
|
Label (Etiqueta)
|
Caption
|
MES
|
1er
|
1
|
Label (Etiqueta)
|
SpecialEffect
|
2 - fmSpecialEffcetSunken
|
2do
|
1
|
Label (Etiqueta)
|
Caption
|
AÑO
|
2do
|
1
|
Label (Etiqueta)
|
SpecialEffect
|
2 - fmSpecialEffcetSunken
|
1er
|
1
|
Combobox (Lista desplegable)
|
Name
|
cbo_Mes
|
1er
|
1
|
Textbox (Cuadro de texto)
|
Name
|
txt_Año
|
1er
|
1
|
SpinButon (Botón de número)
|
Name
|
spn_Año
|
1er
|
1
|
ComandButton (Botón de comando)
|
Name
|
cmd_Ejecutar
|
1er
|
1
|
ComandButton (Botón de comando)
|
Caption
|
EJECUTAR
|
2do
|
1
|
ComandButton (Botón de comando)
|
Name
|
cmd_Cancelar
|
2do
|
1
|
ComandButton (Botón de comando)
|
Caption
|
CANCELAR
|
Se obvia las propiedades Picture y PicturePosition de los botones de comando EJECUTAR y CANCELAR
Ahora agreguemos código de programación que funcione la barra de herramientas.
Seleccione el control Toolbar, presione el botón derecho del mouse y seleccione Ver Código
El evento predeterminado para un control Toolbar es ButtonClick
Desde la ventana de procedimientos cambie el evento a ButtonMenuClick
Y digite el siguiente código:
Ucase es una función de Visual Basic que convierte el texto a Mayúscula. Para minúsculas la función es LCase.
La instrucción Select Case se usa cuando las alternativas en una estructura If Then son muchas. En tal caso conviene evitar If Then y hacer uso de Select Case, que permite ejecutar uno de varios grupos de instrucciones, dependiendo del valor de una expresión.
Sintaxis:
Select Case expresión_prueba
Case expresión 1
Instrucciones 1
Case expresión 2
Instrucciones 2
……….
……….
Case Else
Instrucciones Else
End Select
Líneas atrás, para el submenú REGISTRO DE VENTAS, usted asigno a la propiedad Key el valor REGISTRO DE VENTAS …
Esa propiedad se utiliza como expresión_prueba, luego Select Case ejecuta sólo el bloque de instrucciones que cumplen con la expresión.
Los bloques cuya expresión no coincida con expresión_prueba no se ejecutan, en lenguaje coloquial las sentencias que no cumplen con la expresión_prueba son ignoradas y el cursor en Visual Basic salta de un bloque a otro.
Case Else ejecuta el procedimiento contenido en Instruciones Else en caso expresión_prueba no coincida con los expresiones anteriores.
Para programar la acción en el botón Salir, modifique el procedimiento de la siguiente manera:
Pruebe lo avanzado hasta el momento, ejecute el formulario frm_PLE
Cierre ambos formularios.
Antes de continuar con la programación, es necesario que usted desde MS Excel, nombre una hoja de cálculo como REGISTRO DE VENTAS y agregue los 27 campos o columnas con la estructura publicada para el registro de ventas en la página de SUNAT http://orientacion.sunat.gob.pe/images/imagenes/anexos/8_14Ventas.xls
Estos son los 27 campos + 1 campo adicional que he agregado y al que he llamado TXT
1
|
Número correlativo del registro o el código único de la operación
|
2
|
Fecha de emisión del Comprobante de Pago
|
3
|
Fecha de Vencimiento o Fecha de Pago
|
4
|
Tipo de Comprobante de Pago o Documento
|
5
|
Número serie del comprobante de pago o documento o número de serie de la maquina registradora
|
6
|
Número del comprobante de pago o documento.
En caso de optar por anotar el importe total de las operaciones realizadas diariamente, registrar el número inicial |
7
|
En caso de optar por anotar el importe total de las operaciones realizadas diariamente, registrar el número final.
|
8
|
Número de Documento de Identidad del cliente
|
9
|
Apellidos y nombres, denominación o razón social del cliente
|
10
|
Valor facturado de la exportación
|
11
|
Base imponible de la operación gravada (3)
|
12
|
Importe total de la operación inafecta
|
13
|
ISC, de ser el caso
|
14
|
IGV y/o IPM (4)
|
15
|
Otros tributos y cargos que no forman parte de la base imponible
|
16
|
Importe total del comprobante de pago
|
17
|
Tipo de cambio
|
18
|
Fecha de emisión del comprobante de pago o documento original que se modifica
|
19
|
Tipo del comprobante de pago o documento original que se modifica
|
20
|
Número de serie del comprobante de pago o documento original que se modifica
|
21
|
Número del comprobante de pago o documento original que se modifica.
|
22
|
Tipo de Documento de Identidad del cliente
|
23
|
Periodo
|
24
|
Importe total de la operación exonerada
|
25
|
Base imponible de la operación gravada con el IVAP
|
26
|
IVAP (5)
|
27
|
Indica el estado del comprobante de pago y a la incidencia en la base imponible en relación al periodo tributario correspondiente
|
28
|
TXT
|
La hoja de cálculo deberá de tener la siguiente apariencia:
Ahora vuelva al editor de VB para programar el subformulario frm_REG_VTAS_PLE
Vamos a programar las acciones de los controles cbo_Mes, txt_Año, spn_Año y cmd_Cancelar.
Seleccione el formulario, presione el botón derecho del Mouse y seleccione Ver Código
El evento predeterminado para un formulario es Userform_Click
Desde la ventana de procedimientos cambie el evento a Initialize
Y digite el siguiente código
La primera línea de código selecciona la hoja llamada REGISTRO DE VENTAS
La segunda línea de código declara la variable Mes como Byte
Byte es un tipo de dato que puede contener números que van desde el 0 hasta el 255
Dim es una declaración que reserva un espacio de la memoria para almacenar una variable (en este caso Mes), esta variable permanece almacenada durante la ejecución de la rutina. Cuando termina la rutina, la variable desaparece. Su ámbito de aplicación fue dentro de la rutina, procedimiento, macro o manejador de evento que la contuvo.
Si desea que la variable se mantenga almacenada después de que la rutina termine, entonces debe de declararla como Public, en la sección general del módulo. Las variables declaradas como Public mantiene su valor en memoria y estos valores pueden ser usados en otra rutina, procedimiento, macro o manejador de evento diferente.
Volvamos al tema, la tercera, cuarta y quinta línea de código se conoce como estructura For… Next, esta estructura, comúnmente llamada ciclo o bucle, repite un grupo de instrucciones un número especificado de veces. En este caso en particular la variable Mes toma el valor de 1 hasta 12, es decir el bucle se repite 12 veces.
La instrucción que se a va a repetir 12 veces es: cbo_Mes.AddItem Format(Mes, "00")
Esta instrucción contiene el método AddItem del control combobox llamado Cbo_Mes, el método AddItem agrega Items al combobox, la función Format de VBA le da formato a la variable, para 1 retorna “01”, para 2 retorna “02”… para 12 retorna “12”
Finalmente, la sexta sentencia asigna el valor del año actual para el cuadro de texto txt_Año, para ello se ayuda de la hora de sistema mediante la función Date, luego obtiene el año con la función Year. Ambas funciones de VBA.
Pruebe a digitar VBA.Year, VBA.Date o VBA.Format para que compruebe la jerarquía si lo desea.
Ubique el cursor dentro del procedimiento Private Sub UserForm_Initialize y presione F5 para ejecutar el formulario.
Cierre el formulario, vuelva al editor de VB. Ahora programemos el control de número Spn_Año y el botón de comnado cmd_Cancelar
Seleccione el control Spn_Año, presione el botón derecho del Mouse y elija Ver código.
El evento predeterminado para un control SpinButton es Change
Desde la ventana de procedimientos cambie el evento a SpinDown
Y digite el siguiente código:
Recuerde, cuando el formulario inicia, el valor para el cuadro de texto txt_Año es el año actual, cuando usted presione el botón de número hacia abajo el año actual se reducirá en 1
txt_Año = txt_Año – 1 se lee: El valor actual de txt_Año es igual al valor anterior de txt_Año – 1
De la misma forma proceda para aumentar el año actual en 1, agregando código cuando se presione el botón de número hacia arriba.
Seleccione desde la lista de procedimiento el evento SpinUp y digite txt_Año = txt_Año + 1
Agreguemos código al botón cmd_Cancelar, presione CTRL + R para mostrar el explorador de proyectos, seleccione el formulario frm_REG_VTAS_PLE, presione el botón derecho del Mouse y elija Ver Objeto.
Seleccione el botón de comando cmd_Cancelar, presione el botón derecho del Mouse y elija Ver Código
Digite Unload Me
Esta sentencia descarga el formulario de la memoria, “lo cierra”
Finalmente, agreguemos código al corazón del aplicativo, el botón de comando cmd_Ejecutar
Intente digitar el siguiente código, para evitar ello, le sugiero: imprimir la imagen, escanearla y convertirla a Word mediante ABBY, OCX o similar.
El primer bloque de sentencias utiliza la estructura If…Then y la función Dir para saber si existen las tablas T_COMP.dbf, T_DOC.dbf, REG_VTA1.dbf y REG_VTA2.dbf
Estas tablas no son propias del CONCAR, son tablas temporales que se eliminan mediante la sentencia Kill, al principio y al final del procedimiento, como forma de mantener la base de datos original.
El uso de las tablas temporales se explicara en breve.
Sheets("REGISTRO DE VENTAS").Range("A2:IV65536").ClearContents borra el contenido de las celdas con excepción de la fila 1, la que contiene el encabezado.
Set con = CreateObject("adodb.connection") asigna la referencia CreateObject("adodb.connection") a la variable con, con es la abreviatura de conexión
Las variables de Objeto deben de asignarse mediante Set, a diferencia de otros tipos de variables como Byte, Long, etc.
ADO es la sigla para Active Data Object, ADO es una biblioteca de objeto, se utiliza como intermediario entre el programa y la base de datos, usando ADO podemos traer registros desde una base de datos externa (dbf, sql, access, etc; dependiendo del proveedor) hacia Excel, inclusive desde un libro Excel a otro libro de Excel, o al mismo libro de Excel (Esto lo veríamos en otra ocasión)…o viceversa para llevar registros desde Excel hacia una base de datos externa. Con ADO se puede crear bases datos, tablas, definir campos, registros etc.
Set rs = CreateObject("adodb.recordset") asigna la referencia CreateObject("adodb.recordset") a la variable rs, rs es la abreviatura de recordset
Recordset es el conjunto de registros que vamos a traer desde CONCAR hacia Excel.
ADO tiene tres componentes principales:
- Connection (Permite establecer una conexión con la base de datos)
- Recordset (Maneja un conjunto de registros de la base de datos)
- Command (Permite enviar órdenes SQL para ser ejecutados por la base de datos)
Connection
con.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=W:\REAL\CONCAR80; Extended Properties = dBase 5.0;"
con.Open abre el objeto connection, el método Open va seguido de una cadena de conexión.
La cadena de conexión contiene:
Proveedor, en este caso para un archivo dbf utilizamos Microsoft Jet así: Provider=Microsoft.Jet.OLEDB.4.0
Fuente de datos (Data Source), según la ubicación de la base de datos en su pc, red o servidor, en este caso en esta empresa CONCAR se encuentra ubicado en W:\REAL\CONCAR80
Propiedades extendidas (Extended Properties) en este caso dBase 5.0, es decir el tipo de formato de la base de datos.
Recordset
En la página de SUNAT pueden encontrar la Tabla 10: Tipo de comprobante de pago o documento
En Concar, la tabla CTA02.dbf contiene los tipos de comprobantes SUNAT, clave 06 (Archivo / Tabla General / Mantenimiento Tabla General)
Sin embargo, existe un detalle: El código de comprobante SUNAT no se encuentra almacenado en un campo exclusivo. El código de comprobante SUNAT es un texto de 2 caracteres empezando desde la derecha, con la particularidad que algunos registros no tienen código!!!
Por ello, la necesidad de crear una tabla temporal, que facilite “traducir” los registros contables y los muestre en el Registro de Ventas con el formato tributario.
Por ejemplo, mientras en la base de datos CONCAR, las transacciones de ventas almacena tipos de documento con código BA, en el Registro de Ventas debe de aparece con código 05 para los boletos aéreos.
' CREA TABLA TEMPORAL T_COMP = TIPO DE COMPROBANTE [TABLA 10 SUNAT]
rs.Open "SELECT TCLAVE, VAL(RIGHT(TDESCRI,2)) AS 'TIP_COMP' INTO T_COMP FROM CTA02 WHERE TCOD ='06' AND VAL(RIGHT(TDESCRI,2)) <> 0.0", con
Esta consulta SQL, selecciona los campos TCLAVE y los 2 caracteres derechos del campo TDESCRI de la tabla CTA02 y con un INTO almacena estos registros en una nueva tabla llamada T_COMP, en paralelo aplica un filtro mediante WHERE cuyos criterios son TCOD = 06, es decir, solo los tipos de documentos de la tabla CTA02 y aquellos registros que resulten diferente de 0.0
A continuación la imagen de la tabla temporal T_COMP
Observe como se ha creado el campo XTIP_COMP_ a pesar de que en nuestra consulta SQL se definió como: AS 'TIP_COMP'
Para la tabla 2 de SUNAT el tipo de documento, si es RUC = 6, si es DNI = 1, etc.
En Concar, la tabla CAO02.dbf contiene los tipos de documentos SUNAT
La tabla CAO02.dbf es el detalle de la tabla CAN02.dbf (Archivo / Código de Anexos / Mantenimiento de Anexos)
' CREA TABLA TEMPORAL T_DCTO = TIPO DE DOCUMENTO [TABLA 2 SUNAT]
rs.Open "SELECT DISTINCT AVANEXO, ADOCIDE, ANUMIDE INTO T_DCTO FROM CAO02 WHERE AVANEXO ='C' AND ADOCIDE > '0'", con
Esta consulta SQL selecciona los campos AVANEXO, ADOCIDE y ANUMIDE de la tabla CAO02 y con un INTO almacena, estos registros, en una nueva tabla llamada T_DCTO, en paralelo aplica filtros mediante WHERE cuyos criterios son AVANEXO = C, es decir, sólo los clientes y ADOCIDE <> 0, es decir, aquellos registros que resulten diferente de 0
A continuación la imagen de la tabla temporal T_DCTO
Bien, hasta el momento usted ha creado 2 tablas temporales: T_COMP y T_DCTO
Ahora necesita generar la tabla para el Registro de Ventas, esto lo consigue desde CONCAR (Reportes / Registro de Ventas / Generar Archivo Mensual Ventas)
Para esta empresa, la tabla se crea con el nombre CV031301, donde:
CV = Constante
03 = Empresa
13 = Año
01 = Mes
Para esta empresa, esta tabla contiene los campos necesarios para crear el archivo TXT para SUNAT. A excepción de:
- Periodo
- Importe total de la operación exonerada
- Base imponible de la operación gravada con el IVAP
- IVAP (5)
- Indica el estado del comprobante de pago y a la incidencia en la base imponible en relación al periodo tributario correspondiente
El Periodo se obtiene del formulario que hemos creado líneas atrás.
El Importe total de la operación exonerada, la Base imponible de la operación gravada con el IVAP y el IVAP (5), se obtiene luego de configurar CONCAR, esta empresa no necesita estos campos, por lo que se rellenan con el valor por default 0.00
Para el indicador de estado, se rellena con:
1 = la operación corresponde al periodo
2 = anuladas
Si usted desea registrar la opción 8 ó 9 y rectificar la declaración anterior y pagar la multa e intereses, de ser el caso, edite directamente sobre la hoja de cálculo (columna AA) cuando haya terminado de ejecutar el formulario. Yo no se lo aconsejo.
Volvamos a la programación, el siguiente código crea una nueva tabla temporal llamada REG_VTA1, para ello utiliza INTO luego de relacionar la tabla CV031301 con T_COMP
' CREA TABLA TEMPORAL REG_VTA1 = REGISTRO DE VENTA RELACIONADO CON TABLA 10 SUNAT PARA TIPO DE DOCUMENTO EMITIDO
rs.Open "SELECT VT_SUBDIA + VT_COMPRO AS 'ID', VT_FECDOC, VT_FECDOC + 30 AS 'F_VCTO', FORMAT(T_COMP.XTIP_COMP_,'00') AS 'TCOMP'," & _
" VT_SERDOC, VT_NUMDOC, 0 AS 'NUM_FIN', VT_RUC, VT_NOMBRE, VT_MNEXPO, VT_MNAFEC, VT_MNINAF, VT_MNISC, VT_MNIGV, VT_MNOTR, VT_MNTOTAL," & _
"VT_TIPCAM, VT_REFFEC, FORMAT(IIF(VT_REFTD IS NULL, 'NA',VT_REFTD),'00') AS 'TD_REF', VT_REFSER, VT_REFERE INTO REG_VTA1" & _
" FROM CV03" & Right(txt_Año, 2) & cbo_Mes & " INNER JOIN T_COMP ON CV03" & Right(txt_Año, 2) & cbo_Mes & ".VT_TIPDOC = T_COMP.TCLAVE", con
Note que el nombre de la tabla CV031301 se ha generalizado a CV03" & Right(txt_Año, 2) & cbo_Mes
Se podría generalizar también el código de la empresa, bastaría con adaptarlo con una anterior entrada de este blog.
Right es una función de Visual Basic que devuelve un texto que contiene un número especificado de caracteres desde el lado derecho de una cadena. En este caso la cadena es el año actual 2013, por lo tanto la función devuelve los 2 caracteres derechos, es decir 13.
Cbo_Mes devuelve lo elegido desde el “01” hasta el “12”, visto líneas atrás.
La unión o relación se crea con INNER JOIN los campos relacionados son TIPDOC = TCLAVE
En la figura se muestra como se relaciona 01 para FT, 07 para NC, etc.
También observe que para dividir una línea larga de programación en varias líneas cortas he cerrado el final de cada sentencia con comilla doble (“) seguido de un ampersand (&) y un guión bajo (_). Luego cada linea empieza con una comilla doble (“). De esta forma para fines didácticos usted puede ver todo el código.
Si usted es minucioso, verá que existen otros detalles como el uso de la función Format o la función IFF propia de lenguaje SQL para colocar “NA” para los campos que no cuenten con las referencias propias de una Nota de Crédito o Nota de Debito.
Vea en la siguiente figura, lo que se acaba de mencionar.
Este registro “NA” aún no existe en nuestra tabla temporal tipos de comprobante (TIP_COMP), debemos de agregar este registro mediante un INSERT INTO para que luego pueda ser relacionada correctamente con el Registro de Ventas
TCLAVE = "NA"
XTIP_COMP_ = "00"
Registros_Comprobante = "'" & TCLAVE & "', '" & XTIP_COMP_ & "'"
rs.Open "INSERT INTO T_COMP(TCLAVE, XTIP_COMP_) VALUES(" & Registros_Comprobante & ")", con
TCLAVE y XTIP_COMP_ son los dos campos que contiene la tabla temporal T_COMP (Asegúrese de no haber activado Option Explicit para que el compilador no exija la declaración de variables de manera previa)
Registros_Comprobante es la variable que concatenan los valores y finalmente INSERT INTO es la sentencia que agrega los nuevos registros a la tabla.
En la siguiente imagen, se aprecia el resultado.
Ya tenemos creada la tabla temporal REG_VTA1 ahora creamos la última tabla temporal llamada REG_VTA2
' CREA TABLA TEMPORAL REG_VTA2 = REGISTRO DE VENTA RELACIONADO CON TABLA 10 SUNAT PARA TIPO DE DOCUMENTO REFERENCIA
rs.Open "SELECT XID_, VT_FECDOC, XF_VCTO_, XTCOMP_, VT_SERDOC, VT_NUMDOC, XNUM_FIN_, VT_RUC, VT_NOMBRE, VT_MNEXPO, VT_MNAFEC, VT_MNINAF," & _
" VT_MNISC, VT_MNIGV, VT_MNOTR, VT_MNTOTAL, VT_TIPCAM, VT_REFFEC, XTIP_COMP_, VT_REFSER, VT_REFERE INTO REG_VTA2" & _
" FROM REG_VTA1 INNER JOIN T_COMP ON REG_VTA1.XTD_REF_ = T_COMP.TCLAVE", con
REG_VTA2 se crea a partir de REG_VTA1 mediante un INTO, luego de relacionar REG_VTA1 con T_COMP, esta vez para cambiar FT por 01, NC por 07. ND por 08 para los campos de referencia, es decir cuando se emiten Notas de Crédito y/o Notas de Débito, es exigencia que el Registro de Ventas identifique el comprobante que dio origen a los ajustes.
Finalmente, a la tabla temporal REG_VTA2 se le relaciona con la tabla temporal T_DCTO para obtener le Registro de Ventas definitivo
' AL REGISTRO DE VENTA TEMPORAL LE AGREGA EL CAMPO TIPO DE DOCUMENTO [TABLA 2 SUNAT]
rs.Open "SELECT REG_VTA2.*, T_DCTO.ADOCIDE FROM REG_VTA2 INNER JOIN T_DCTO ON REG_VTA2.VT_RUC = T_DCTO.ANUMIDE", con
La relación se crea uniendo los campos VT_RUC = ANUMIDE, es decir el número de RUC.
Esta selección hace posible reemplazar los códigos que CONCAR para los tipos de documentos, y mostrar su equivalente según SUNAT, ejemplo: DNI = 01, RUC = 06, etc.
Sheets("REGISTRO DE VENTAS").Range("A2").CopyFromRecordset rs
Con esta sentencia los datos obteniendos mediante SQL se vuelcan sobre la celda A2 de la hoja de cálculo llamada REGISTRO DE VENTAS.
Set rs = Nothing
Set con = Nothing
Estas sentencias liberan de la memoria las variables rs y con
Sheets("REGISTRO DE VENTAS").Range("W2:W" & Range("A65536").End(xlUp).Row & "").Formula = "'" & txt_Año & cbo_Mes & "00"
Esta sentencia rellena la columna W con el Periodo en el formato solicitado por SUNAT, por ejemplo: 20130100
Como el número de filas o registros es indeterminado o variable cada mes o en cada empresa, hacemos referencia absoluta a A65536 (Excel 2003 o inferior), para luego mover el cursor hacia arriba y obtener el número de la última fila o registro.
Sheets("REGISTRO DE VENTAS").Range("X2:Z" & Range("A65536").End(xlUp).Row & "").Formula = 0
Esta sentencia rellena desde la columna X hasta la columna Z con “0” para la columna de Importe total de la operación exonerada, Base imponible de la operación gravada con el IVAP e IVAP (5), correspondientemente.
Dim Estado As Long
For Estado = 2 To Sheets("REGISTRO DE VENTAS").Range("A65536").End(xlUp).Row
If Cells(Estado, 18) = "" Then
Cells(Estado, 18) = "'" & "01/01/0001"
End If
If Cells(Estado, 19) = "" Then
Cells(Estado, 19) = "'" & "00"
End If
If Cells(Estado, 20) = "" Then
Cells(Estado, 20) = "'" & "-"
End If
If Cells(Estado, 21) = "" Then
Cells(Estado, 21) = "'" & "-"
End If
If Cells(Estado, 9) = "ANULADA" Then
Cells(Estado, 22) = "'" & 0
Cells(Estado, 27) = "2"
Else
Cells(Estado, 27) = "1"
End If
Next Estado
La primera línea, de este grupo de sentencias, declara la variable Estado como Long.
Long es un tipo de datos que representa un número entero que puede ir desde: -2,147,483,648 hasta 2,147,483,647, es decir un número mayor al número de filas que puede contener una hoja de cálculo actualmente.
Luego viene un bucle For…Next, que va desde la fila número 2 hasta la última fila que contenga el Registro de Ventas. Nuevamente hacemos referencia absoluta a A65536 (Excel 2003 o inferior), para luego mover el cursor hacia arriba y obtener el número de la última fila o registro.
Comparamos el valor de la columna 18 (Fecha de emisión del comprobante de pago o documento original que se modifica) si es igual a vacío entonces rellenamos la celda con “01/01/0001”, tal como solicita SUNAT.
Comparamos el valor de la columna 19 (Tipo del comprobante de pago o documento original que se modifica) si es igual a vacío entonces rellenamos la celda con “00”, tal como solicita SUNAT.
Comparamos el valor de la columna 20 (Número de serie del comprobante de pago o documento original que se modifica) si es igual a vacío entonces rellenamos la celda con “-”, tal como solicita SUNAT.
Comparamos el valor de la columna 21 (Número del comprobante de pago o documento original que se modifica.) si es igual a vacío entonces rellenamos la celda con “-”, tal como solicita SUNAT.
Comparamos el valor de la columna 9 (Apellidos y nombres, denominación o razón social del cliente) si es igual a ANULADA entonces:
Rellenamos la columna 22 (Tipo de Documento de Identidad del cliente) con “0”, tal como solicita SUNAT.
Rellenamos la columna 27 (Indica el estado del comprobante de pago y a la incidencia en la base imponible en relación al periodo tributario correspondiente) con 2, tal como solicita SUNAT.
Si el valor de la columna 9 es diferente de ANULADA entonces rellenamos la columna 27 (Indica el estado del comprobante de pago y a la incidencia en la base imponible en relación al periodo tributario correspondiente) con 1, tal como solicita SUNAT.
Sheets("REGISTRO DE VENTAS").Range("AB2:AB" & Range("A65536").End(xlUp).Row & "").Formula = "=RC[-5]&""|""&RC[-27]&""|""&TEXT(RC[-26]," & _
"""DD/MM/YYYY"")&""|""&TEXT(RC[-25],""DD/MM/YYYY"")&""|""&RC[-24]&""|""&TEXT(RC[-23],""0000"")&""|""&RC[-22]&""|""&RC[-21]&""|""&RC" & _
"[-6]&""|""&IF(RC[-6]=""1"",RIGHT(RC[-20],8),RC[-20])&""|""&RC[-19]&""|""&TEXT(RC[-18],""0.00"")&""|""&TEXT(RC[-17],""0.00"")&""|""&TEXT" & _
"(RC[-4],""0.00"")&""|""&TEXT(RC[-16],""0.00"")&""|""&TEXT(RC[-15],""0.00"")&""|""&TEXT(RC[-14],""0.00"")&""|""&TEXT(RC" & _
"[-3],""0.00"")&""|""&TEXT(RC[-2],""0.00"")&""|""&TEXT(RC[-13],""0.00"")&""|""&TEXT(RC[-12],""0.00"")&""|""&TEXT(RC[-11],""0.000"")&""|""&TEXT" & _
"(RC[-10],""DD/MM/YYYY"")&""|""&TEXT(RC[-9],""00"")&""|""&TEXT(RC[-8],""0000"")&""|""&RC[-7]&""|""&RC[-1]&""|"""
Esta sentencia rellena la columna AB (columna adicional que hemos llamado TXT), con una fórmula de concatenación, dentro de la fórmula se aprecia la función TEXT para formatear de acuerdo a lo requerido por SUNAT, asimismo el uso de la barra vertical “|” como separador de campos.
If Dir("W:\REAL\CONCAR80\T_COMP.dbf") <> "" Then
Kill ("W:\REAL\CONCAR80\T_COMP.DBF")
End If
If Dir("W:\REAL\CONCAR80\T_DCTO.dbf") <> "" Then
Kill ("W:\REAL\CONCAR80\T_DCTO.DBF")
End If
If Dir("W:\REAL\CONCAR80\REG_VTA1.dbf") <> "" Then
Kill ("W:\REAL\CONCAR80\REG_VTA1.DBF")
End If
If Dir("W:\REAL\CONCAR80\REG_VTA2.dbf") <> "" Then
Kill ("W:\REAL\CONCAR80\REG_VTA2.DBF")
End If
Con estas sentencias se inicia y se termina el procedimiento, si por algún motivo las tablas temporales existen, Kill se encarga de eliminarlas, como ya se explico, previamente usamos Dir para saber si existen.
Unload Me
Esta sentencia descarga el formulario de la memoria.
Nota:
A propósito se han dejado expuestos los datos en la hoja de cálculo (con motivo de revisión previa al envío) asícomo la columna AB que contiene la estructura TXT para copiar y pegar en el block de notas y guardarlo con el nombre que solicita SUNAT.
Sin embargo usted puede ir más allá y copiar la columna AB como valores en una nueva hoja de cálculo
Luego tendría que agregar un código similar a:
RUC = InputBox("Ingrese RUC")
Nombre_Archivo_TXT = "LE" & RUC & txt_Año & txt_Mes & "00140100001111"
ActiveWorkbook.SaveAs Filename:="C:\" & Nombre_Archivo_TXT & ".txt", FileFormat:=xlText, CreateBackup:=False
Donde RUC es una variable que guarda el número de RUC digitado en un Inputbox.
En la variable Nombre_Archivo_TXT se guarda el nombre del archivo según lo requiere SUNAT.
Finalmente, se guarda el archivo como TXT en la carpeta o directorio C.
A continuación, alguna imágenes finales que resumen el proceso hasta su consistencia con el programa de libros electrónicos PLE 3.0 SUNAT
Este desarrollo ha sido (como su nombre lo indica) un ejemplo, le deseo suerte y espero que le sirva como guía para llevar a cabo este proyecto en su empresa. Así también como guía para quienes se inician en la programación con VBA de Excel.
Si usted, piensa copiar y/o adaptar este proyecto en otra página web, le pido que por favor, haga referencia mediante un vínculo a este blog.
Les doy gracias a las empresas que me han contactado para llevar cabo sus proyectos de migración hacia CONCAR.
Por último, no olviden que lo explicado es adaptable a cualquier otro software, por nombrar uno de ellos: a SAP Business One, tendrían que apuntar a la tabla de diario OJTD y /o validar con la tabla de Facturación OINV, obviamente los campos cambian pero no seria necesario crear las tablas temporales, el proveedor de la base datos es sqloledb, entre otros detalles.
Saludos y Exitos!!!
Muy buen aporte, te felicito.
ResponderEliminarAmigo tiene un correo elctronico por medio del cual se puede comunicar con Ud, queremos realizar importaciones al CONCAR de compras que efectuamos a nuestros proveedores, sin embargo como son una gran cantidad, nos gustaria saber si podemos importar al CONCAR de un archivo DBF, por favor su ayuda sera remunerada, a espera de sus datos
ResponderEliminarHola!
EliminarMi correo electrónico es: abraham.ramirez.villavicencio@gmail.com
Saludos,
Abraham
Hola todo esto crees que pueda servir?
EliminarNo valida nada este programa, creo que lo hiciste a la volada.
Saludos
Para validar existe el propio validador de la SUNAT
EliminarHOLA Y LA HOJA MACROS NOS LA PODIAS PASAR PORFAVOR
ResponderEliminarpedroh7678@gmail.com
ResponderEliminar