arcli 1.7.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/CHANGELOG.md +78 -1
  2. package/README.md +11 -18
  3. package/dist/cli/commands/billing.command.options.js +17 -15
  4. package/dist/cli/commands/billing.command.options.js.map +1 -1
  5. package/dist/cli/commands/billing.command.parser.js +57 -28
  6. package/dist/cli/commands/billing.command.parser.js.map +1 -1
  7. package/dist/cli/commands/billing.command.pdf.d.ts +1 -1
  8. package/dist/cli/commands/billing.command.pdf.js +17 -2
  9. package/dist/cli/commands/billing.command.pdf.js.map +1 -1
  10. package/dist/cli/commands/config.command.js +4 -2
  11. package/dist/cli/commands/config.command.js.map +1 -1
  12. package/dist/cli/commands/vouchers.command.js +7 -6
  13. package/dist/cli/commands/vouchers.command.js.map +1 -1
  14. package/dist/cli/error-output.d.ts +7 -0
  15. package/dist/cli/error-output.js +26 -0
  16. package/dist/cli/error-output.js.map +1 -0
  17. package/dist/cli/help-argv.d.ts +5 -0
  18. package/dist/cli/help-argv.js +21 -0
  19. package/dist/cli/help-argv.js.map +1 -0
  20. package/dist/cli/help.js +4 -3
  21. package/dist/cli/help.js.map +1 -1
  22. package/dist/cli/index.js +14 -20
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/cli/interactive/advanced-options.js +2 -2
  25. package/dist/cli/interactive/advanced-options.js.map +1 -1
  26. package/dist/cli/interactive/config.flow.d.ts +1 -1
  27. package/dist/cli/interactive/config.flow.js +53 -18
  28. package/dist/cli/interactive/config.flow.js.map +1 -1
  29. package/dist/cli/interactive/history.flow.d.ts +4 -0
  30. package/dist/cli/interactive/history.flow.js +22 -8
  31. package/dist/cli/interactive/history.flow.js.map +1 -1
  32. package/dist/cli/interactive/interactive-mode.js +99 -17
  33. package/dist/cli/interactive/interactive-mode.js.map +1 -1
  34. package/dist/cli/interactive/invoice-picker.d.ts +25 -0
  35. package/dist/cli/interactive/invoice-picker.js +153 -0
  36. package/dist/cli/interactive/invoice-picker.js.map +1 -0
  37. package/dist/cli/interactive/note.flow.d.ts +8 -2
  38. package/dist/cli/interactive/note.flow.js +39 -37
  39. package/dist/cli/interactive/note.flow.js.map +1 -1
  40. package/dist/cli/interactive/pdf.flow.js +33 -22
  41. package/dist/cli/interactive/pdf.flow.js.map +1 -1
  42. package/dist/cli/interactive/prompts.d.ts +36 -5
  43. package/dist/cli/interactive/prompts.js +185 -19
  44. package/dist/cli/interactive/prompts.js.map +1 -1
  45. package/dist/cli/interactive/repeat.flow.js +26 -17
  46. package/dist/cli/interactive/repeat.flow.js.map +1 -1
  47. package/dist/cli/interactive/status.flow.d.ts +3 -0
  48. package/dist/cli/interactive/status.flow.js +29 -0
  49. package/dist/cli/interactive/status.flow.js.map +1 -0
  50. package/dist/cli/interactive/update.flow.d.ts +6 -0
  51. package/dist/cli/interactive/update.flow.js +26 -0
  52. package/dist/cli/interactive/update.flow.js.map +1 -0
  53. package/dist/cli/interactive/validators.js +8 -4
  54. package/dist/cli/interactive/validators.js.map +1 -1
  55. package/dist/cli/option-parsers.d.ts +6 -0
  56. package/dist/cli/option-parsers.js +34 -0
  57. package/dist/cli/option-parsers.js.map +1 -0
  58. package/dist/cli/version.d.ts +1 -1
  59. package/dist/cli/version.js +1 -1
  60. package/dist/lib/dates/arca-date.d.ts +13 -0
  61. package/dist/lib/dates/arca-date.js +28 -11
  62. package/dist/lib/dates/arca-date.js.map +1 -1
  63. package/dist/lib/errors/app-error.d.ts +3 -0
  64. package/dist/lib/errors/app-error.js +3 -0
  65. package/dist/lib/errors/app-error.js.map +1 -1
  66. package/dist/lib/files/restrict-to-owner.d.ts +7 -0
  67. package/dist/lib/files/restrict-to-owner.js +19 -0
  68. package/dist/lib/files/restrict-to-owner.js.map +1 -0
  69. package/dist/lib/identity/format-cuit.d.ts +2 -0
  70. package/dist/lib/identity/format-cuit.js +6 -0
  71. package/dist/lib/identity/format-cuit.js.map +1 -0
  72. package/dist/lib/numbers/argentine-amount.d.ts +23 -0
  73. package/dist/lib/numbers/argentine-amount.js +37 -0
  74. package/dist/lib/numbers/argentine-amount.js.map +1 -0
  75. package/dist/lib/numbers/strict-integer.d.ts +4 -0
  76. package/dist/lib/numbers/strict-integer.js +10 -0
  77. package/dist/lib/numbers/strict-integer.js.map +1 -0
  78. package/dist/lib/security/pem.js +5 -1
  79. package/dist/lib/security/pem.js.map +1 -1
  80. package/dist/modules/billing/billing-response.js +3 -2
  81. package/dist/modules/billing/billing-response.js.map +1 -1
  82. package/dist/modules/billing/billing.amounts.d.ts +2 -0
  83. package/dist/modules/billing/billing.amounts.js +6 -3
  84. package/dist/modules/billing/billing.amounts.js.map +1 -1
  85. package/dist/modules/billing/billing.associated-vouchers.js +14 -3
  86. package/dist/modules/billing/billing.associated-vouchers.js.map +1 -1
  87. package/dist/modules/billing/billing.batch.js +6 -0
  88. package/dist/modules/billing/billing.batch.js.map +1 -1
  89. package/dist/modules/billing/billing.date-range.js +14 -9
  90. package/dist/modules/billing/billing.date-range.js.map +1 -1
  91. package/dist/modules/billing/billing.display.js +4 -4
  92. package/dist/modules/billing/billing.display.js.map +1 -1
  93. package/dist/modules/billing/billing.errors.d.ts +12 -0
  94. package/dist/modules/billing/billing.errors.js +18 -0
  95. package/dist/modules/billing/billing.errors.js.map +1 -0
  96. package/dist/modules/billing/billing.schemas.js +13 -5
  97. package/dist/modules/billing/billing.schemas.js.map +1 -1
  98. package/dist/modules/billing/billing.service.js +10 -3
  99. package/dist/modules/billing/billing.service.js.map +1 -1
  100. package/dist/modules/billing/billing.validation.js +4 -0
  101. package/dist/modules/billing/billing.validation.js.map +1 -1
  102. package/dist/modules/config/config-value-parser.d.ts +1 -1
  103. package/dist/modules/config/config-value-parser.js +21 -9
  104. package/dist/modules/config/config-value-parser.js.map +1 -1
  105. package/dist/modules/config/config.presenter.d.ts +4 -0
  106. package/dist/modules/config/config.presenter.js +57 -37
  107. package/dist/modules/config/config.presenter.js.map +1 -1
  108. package/dist/modules/config/config.schemas.d.ts +4 -2
  109. package/dist/modules/config/config.schemas.js +4 -0
  110. package/dist/modules/config/config.schemas.js.map +1 -1
  111. package/dist/modules/config/config.sections.d.ts +14 -0
  112. package/dist/modules/config/config.sections.js +61 -0
  113. package/dist/modules/config/config.sections.js.map +1 -0
  114. package/dist/modules/config/config.service.d.ts +5 -0
  115. package/dist/modules/config/config.service.js +30 -6
  116. package/dist/modules/config/config.service.js.map +1 -1
  117. package/dist/modules/examples/examples.js +5 -1
  118. package/dist/modules/examples/examples.js.map +1 -1
  119. package/dist/modules/interactive/amount-input.d.ts +3 -5
  120. package/dist/modules/interactive/amount-input.js +9 -26
  121. package/dist/modules/interactive/amount-input.js.map +1 -1
  122. package/dist/modules/interactive/config-fields.d.ts +1 -3
  123. package/dist/modules/interactive/config-fields.js +37 -42
  124. package/dist/modules/interactive/config-fields.js.map +1 -1
  125. package/dist/modules/interactive/equivalent-command.js +6 -8
  126. package/dist/modules/interactive/equivalent-command.js.map +1 -1
  127. package/dist/modules/interactive/invoice-copy.d.ts +19 -0
  128. package/dist/modules/interactive/invoice-copy.js +26 -0
  129. package/dist/modules/interactive/invoice-copy.js.map +1 -0
  130. package/dist/modules/interactive/periods.d.ts +2 -2
  131. package/dist/modules/interactive/periods.js +8 -4
  132. package/dist/modules/interactive/periods.js.map +1 -1
  133. package/dist/modules/parameters/health.d.ts +17 -0
  134. package/dist/modules/parameters/health.js +29 -0
  135. package/dist/modules/parameters/health.js.map +1 -0
  136. package/dist/modules/pdf/pdf.errors.d.ts +0 -1
  137. package/dist/modules/pdf/pdf.errors.js +1 -3
  138. package/dist/modules/pdf/pdf.errors.js.map +1 -1
  139. package/dist/modules/storybook/showcase.js +4 -1
  140. package/dist/modules/storybook/showcase.js.map +1 -1
  141. package/dist/modules/update-check/changelog.d.ts +23 -0
  142. package/dist/modules/update-check/changelog.js +99 -0
  143. package/dist/modules/update-check/changelog.js.map +1 -0
  144. package/dist/modules/update-check/update-check.presenter.d.ts +4 -0
  145. package/dist/modules/update-check/update-check.presenter.js +80 -2
  146. package/dist/modules/update-check/update-check.presenter.js.map +1 -1
  147. package/dist/modules/update-check/update-check.service.d.ts +3 -0
  148. package/dist/modules/update-check/update-check.service.js +2 -2
  149. package/dist/modules/update-check/update-check.service.js.map +1 -1
  150. package/dist/modules/vouchers/voucher-history.d.ts +9 -4
  151. package/dist/modules/vouchers/voucher-history.js +8 -3
  152. package/dist/modules/vouchers/voucher-history.js.map +1 -1
  153. package/dist/modules/vouchers/voucher-history.presenter.d.ts +9 -2
  154. package/dist/modules/vouchers/voucher-history.presenter.js +53 -15
  155. package/dist/modules/vouchers/voucher-history.presenter.js.map +1 -1
  156. package/dist/services/arca/arca-context.resolver.js +5 -0
  157. package/dist/services/arca/arca-context.resolver.js.map +1 -1
  158. package/dist/services/clipboard/clipboard.d.ts +2 -0
  159. package/dist/services/clipboard/clipboard.js +17 -0
  160. package/dist/services/clipboard/clipboard.js.map +1 -0
  161. package/dist/services/pdf/escape-html.d.ts +6 -0
  162. package/dist/services/pdf/escape-html.js +25 -0
  163. package/dist/services/pdf/escape-html.js.map +1 -0
  164. package/dist/services/pdf/pdf-exporter.js +2 -1
  165. package/dist/services/pdf/pdf-exporter.js.map +1 -1
  166. package/dist/ui/components/statusBar.d.ts +15 -2
  167. package/dist/ui/components/statusBar.js +18 -9
  168. package/dist/ui/components/statusBar.js.map +1 -1
  169. package/dist/ui/presenters/errors.presenter.js +5 -4
  170. package/dist/ui/presenters/errors.presenter.js.map +1 -1
  171. package/dist/ui/primitives/renderLogo.d.ts +2 -1
  172. package/dist/ui/primitives/renderLogo.js +21 -4
  173. package/dist/ui/primitives/renderLogo.js.map +1 -1
  174. package/dist/ui/primitives/renderPanel.d.ts +2 -0
  175. package/dist/ui/primitives/renderPanel.js +15 -5
  176. package/dist/ui/primitives/renderPanel.js.map +1 -1
  177. package/dist/ui/stream/terminal-stream.d.ts +6 -0
  178. package/dist/ui/stream/terminal-stream.js +15 -1
  179. package/dist/ui/stream/terminal-stream.js.map +1 -1
  180. package/dist/ui/theme/theme.d.ts +3 -3
  181. package/dist/ui/theme/theme.js +14 -3
  182. package/dist/ui/theme/theme.js.map +1 -1
  183. package/llms.txt +12 -10
  184. package/package.json +1 -1
  185. package/dist/cli/interactive/lookup.flow.d.ts +0 -5
  186. package/dist/cli/interactive/lookup.flow.js +0 -72
  187. package/dist/cli/interactive/lookup.flow.js.map +0 -1
@@ -1,14 +1,22 @@
1
+ import { Separator } from '@inquirer/select';
2
+ import { formatCuit } from '../../lib/identity/format-cuit.js';
1
3
  import { ConfigService } from '../../modules/config/config.service.js';
2
4
  import { listMissingSetupKeys } from '../../modules/interactive/config-fields.js';
5
+ import { checkArcaHealth } from '../../modules/parameters/health.js';
6
+ import { checkForUpdate } from '../../modules/update-check/update-check.service.js';
7
+ import { ArcaParametersGateway } from '../../services/arca/arca-parameters.gateway.js';
3
8
  import { colorize, formatCliError, noticePanel, renderLogo, statusBar, writeTerminalError, writeTerminalOutput, } from '../../ui/index.js';
9
+ import { startSpinner } from '../spinner.js';
10
+ import { CLI_VERSION } from '../version.js';
4
11
  import { runConfigMenu, runGuidedSetup } from './config.flow.js';
5
12
  import { runHistoryFlow } from './history.flow.js';
6
13
  import { runInvoiceFlow } from './invoice.flow.js';
7
- import { runLookupFlow, runStatusFlow } from './lookup.flow.js';
8
14
  import { runNoteFlow } from './note.flow.js';
9
15
  import { chooseOne, confirm, isPromptCancellation } from './prompts.js';
10
16
  import { runRepeatFlow } from './repeat.flow.js';
11
17
  import { createInteractiveSession } from './session.js';
18
+ import { runStatusFlow } from './status.flow.js';
19
+ import { runUpdateFlow } from './update.flow.js';
12
20
  function listMissingSetup() {
13
21
  const service = new ConfigService();
14
22
  try {
@@ -42,34 +50,87 @@ async function runOption(option, options) {
42
50
  await runInvoiceFlow(session);
43
51
  if (option === 'repetir')
44
52
  await runRepeatFlow(session);
45
- if (option === 'nota')
46
- await runNoteFlow(session);
53
+ if (option === 'nota-credito')
54
+ await runNoteFlow(session, 'credito');
55
+ if (option === 'nota-debito')
56
+ await runNoteFlow(session, 'debito');
47
57
  if (option === 'historial')
48
58
  await runHistoryFlow(session);
49
- if (option === 'consultar')
50
- await runLookupFlow(session);
51
59
  if (option === 'estado')
52
60
  await runStatusFlow(session);
53
61
  }
54
- function formatHeader(options) {
62
+ const HEALTH_LABELS = {
63
+ 'con-demoras': ['ARCA con demoras', 'warning'],
64
+ 'con-problemas': ['ARCA con problemas', 'danger'],
65
+ funcionando: ['ARCA funcionando', 'success'],
66
+ 'sin-respuesta': ['ARCA sin respuesta', 'danger'],
67
+ };
68
+ function tryResolveSession(options) {
55
69
  try {
56
- const { environment, pointOfSale } = createInteractiveSession(options).runtime;
57
- return statusBar('Modo interactivo', `${environment} · PV ${pointOfSale ?? 'sin configurar'}`, environment === 'produccion' ? 'danger' : 'warning');
70
+ return createInteractiveSession(options);
58
71
  }
59
72
  catch {
60
- return statusBar('Modo interactivo', 'falta completar la configuracion', 'warning');
73
+ return undefined;
74
+ }
75
+ }
76
+ /** La razon social, si es tan larga que no entra en la barra, se corta. */
77
+ const MAX_ISSUER_NAME_LENGTH = 32;
78
+ /**
79
+ * Barra de estado: a la izquierda, quien emite (razon social, o el CUIT si no esta configurada) y el punto de
80
+ * venta; a la derecha, como esta ARCA y el entorno, cada uno en su color.
81
+ */
82
+ async function buildHeader(options) {
83
+ const session = tryResolveSession(options);
84
+ if (!session) {
85
+ return statusBar([{ text: 'falta completar la configuracion' }], [{ color: 'muted', text: 'ARCA SIN VERIFICAR' }]);
86
+ }
87
+ const spinner = startSpinner('Consultando el estado de ARCA...');
88
+ const health = await checkArcaHealth({ gateway: new ArcaParametersGateway(session.arca) });
89
+ spinner?.stop();
90
+ const [label, color] = HEALTH_LABELS[health];
91
+ const { config, context, environment, pointOfSale } = session.runtime;
92
+ return statusBar([
93
+ { text: formatIssuer(config.emisor?.razonSocial, context.cuit) },
94
+ { text: `PV ${pointOfSale ?? 'sin configurar'}` },
95
+ ], [
96
+ { color, text: label.toUpperCase() },
97
+ environment === 'produccion'
98
+ ? { color: 'production', text: 'PRODUCCION' }
99
+ : { color: 'testing', text: 'TESTING' },
100
+ ], { rightSeparator: 'rule' });
101
+ }
102
+ function formatIssuer(businessName, cuit) {
103
+ if (!businessName) {
104
+ return formatCuit(cuit);
61
105
  }
106
+ return businessName.length > MAX_ISSUER_NAME_LENGTH
107
+ ? `${businessName.slice(0, MAX_ISSUER_NAME_LENGTH - 1).trimEnd()}…`
108
+ : businessName;
109
+ }
110
+ function updateChoice(update) {
111
+ const name = `Actualizar a la version ${update.latestVersion}`;
112
+ return { name: colorize(name, 'highlight'), short: name, value: 'actualizar' };
62
113
  }
63
114
  /** Asistente paso a paso encima del CLI. Ctrl+C cancela el flujo actual; en el menu, sale. */
64
115
  export async function runInteractiveMode(options = {}) {
65
- // Mismo aire debajo del logo que arriba: tres lineas en blanco.
66
- writeTerminalOutput([renderLogo().trimEnd(), '', '', '', formatHeader(options)].join('\n'));
116
+ // En el modo interactivo se consulta npm siempre (no una vez por dia): la consulta va en paralelo con ARCA.
117
+ const updatePromise = checkForUpdate(CLI_VERSION, { maxAgeMs: 0 }).catch(() => null);
118
+ // Dos lineas en blanco entre el logo y la barra. La barra se escribe aparte porque, mientras se consulta ARCA,
119
+ // en su lugar va el spinner. Debajo, una linea en blanco fija: al responder el menu, @inquirer saca las lineas
120
+ // de su prefijo y sin esta la respuesta quedaria pegada a la barra (ver `compactTop` en el primer menu).
121
+ process.stdout.write(`${renderLogo(CLI_VERSION).trimEnd()}\n\n\n`);
122
+ process.stdout.write(`${await buildHeader(options)}\n\n`);
123
+ const update = await updatePromise;
124
+ // El menu va justo debajo de la barra solo la primera vez; despues, debajo de lo que mostro cada flujo.
125
+ let menuUnderHeader = true;
67
126
  // Primera vez: sin CUIT, certificado o punto de venta no se puede hacer nada, asi que se ofrece la guia.
68
127
  if (listMissingSetup().length > 0) {
128
+ menuUnderHeader = false;
69
129
  try {
70
130
  if (await confirm('Falta completar la configuracion. ¿La hacemos ahora, paso a paso?', 'Si, configurar', 'Despues')) {
71
131
  await runGuidedSetup();
72
- writeTerminalOutput(formatHeader(options));
132
+ writeTerminalOutput(await buildHeader(options));
133
+ menuUnderHeader = true;
73
134
  }
74
135
  }
75
136
  catch (error) {
@@ -82,19 +143,34 @@ export async function runInteractiveMode(options = {}) {
82
143
  let option;
83
144
  try {
84
145
  option = await chooseOne('¿Que queres hacer?', [
146
+ ...(update ? [updateChoice(update), new Separator(' ')] : []),
85
147
  { name: 'Emitir factura', value: 'factura' },
86
148
  {
87
149
  description: 'Copia una de las ultimas, con fechas nuevas',
88
150
  name: 'Repetir una factura anterior',
89
151
  value: 'repetir',
90
152
  },
91
- { name: 'Nota de credito o debito sobre una factura', value: 'nota' },
92
- { name: 'Ver ultimos comprobantes', value: 'historial' },
93
- { name: 'Consultar un comprobante', value: 'consultar' },
153
+ {
154
+ description: 'Descuento, devolucion o anulacion de una factura',
155
+ name: 'Emitir nota de credito',
156
+ value: 'nota-credito',
157
+ },
158
+ { description: 'Cargo adicional sobre una factura', name: 'Emitir nota de debito', value: 'nota-debito' },
159
+ {
160
+ description: 'Los ultimos de cada tipo, o buscar uno por numero',
161
+ name: 'Consultar comprobantes',
162
+ value: 'historial',
163
+ },
94
164
  { description: 'Servidores, punto de venta y cotizacion del dolar', name: 'Estado de ARCA', value: 'estado' },
95
- { description: 'Revisar, configuracion guiada, cambiar un dato y PDF', name: 'Configuracion', value: 'config' },
165
+ {
166
+ description: 'Revisar, configuracion guiada, cambiar un dato y PDF',
167
+ name: 'Configuracion',
168
+ value: 'config',
169
+ },
170
+ new Separator(' '),
96
171
  { name: 'Salir', value: 'salir' },
97
- ]);
172
+ ], undefined, { compactTop: menuUnderHeader, escapeLabel: 'salir', escapeValue: 'salir' });
173
+ menuUnderHeader = false;
98
174
  }
99
175
  catch (error) {
100
176
  if (isPromptCancellation(error)) {
@@ -106,6 +182,12 @@ export async function runInteractiveMode(options = {}) {
106
182
  break;
107
183
  }
108
184
  try {
185
+ if (option === 'actualizar') {
186
+ if (update && (await runUpdateFlow(update))) {
187
+ return;
188
+ }
189
+ continue;
190
+ }
109
191
  await runOption(option, options);
110
192
  }
111
193
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-mode.js","sourceRoot":"","sources":["../../../src/cli/interactive/interactive-mode.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"interactive-mode.js","sourceRoot":"","sources":["../../../src/cli/interactive/interactive-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { VoucherKindDefinition } from '../../modules/billing/billing.types';
2
+ import { type Back } from '../../modules/interactive/wizard';
3
+ import { type IssuedVoucher } from '../../modules/vouchers/voucher-history';
4
+ import type { InteractiveSession } from './session';
5
+ /** Comprobante elegido y el punto de venta donde se emitio (a mano puede ser otro que el configurado). */
6
+ export interface PickedInvoice {
7
+ readonly invoice: IssuedVoucher;
8
+ readonly pointOfSale: number;
9
+ }
10
+ interface PickInvoiceOptions {
11
+ readonly message: string;
12
+ /**
13
+ * Modo explorar: en vez de devolver el elegido, lo pasa aca y vuelve a mostrar la lista sin perder lo cargado.
14
+ * Solo se sale con "Volver".
15
+ */
16
+ readonly onPick?: (picked: PickedInvoice) => Promise<void> | void;
17
+ readonly pointOfSale: number;
18
+ readonly voucherKind: VoucherKindDefinition;
19
+ }
20
+ /**
21
+ * Elegir un comprobante emitido: los ultimos del punto de venta configurado, con opciones para cargar mas
22
+ * o ingresar el numero a mano (por ejemplo, uno viejo o de otro punto de venta).
23
+ */
24
+ export declare function pickInvoice(session: InteractiveSession, options: PickInvoiceOptions): Promise<Back | PickedInvoice>;
25
+ export {};
@@ -0,0 +1,153 @@
1
+ import { Separator } from '@inquirer/select';
2
+ import { BACK } from '../../modules/interactive/wizard.js';
3
+ import { listVouchersFrom, RECENT_VOUCHERS_LIMIT } from '../../modules/vouchers/voucher-history.js';
4
+ import { formatVoucherNumber, formatVoucherPickerRows } from '../../modules/vouchers/voucher-history.presenter.js';
5
+ import { colorize, noticePanel, statusBarWidth, writeTerminalOutput } from '../../ui/index.js';
6
+ import { startSpinner } from '../spinner.js';
7
+ import { askTextStep, chooseStep, chooseStepWhileLoading, eraseLastAnswer, fitPageSize } from './prompts.js';
8
+ const LOAD_MORE = 'cargar-mas';
9
+ const BY_NUMBER = 'a-mano';
10
+ /** Separa las columnas de cada fila del listado. */
11
+ const COLUMN_SEPARATOR = ' · ';
12
+ /**
13
+ * Linea punteada tenue que enmarca el listado, del mismo ancho que la barra de estado de ARCA.
14
+ * @inquirer deja un espacio antes de cada separador; por eso se resta uno al ancho.
15
+ */
16
+ function listRule() {
17
+ return new Separator(colorize('┈'.repeat(statusBarWidth() - 1), 'muted'));
18
+ }
19
+ async function withSpinner(text, run) {
20
+ const spinner = startSpinner(text);
21
+ try {
22
+ return await run();
23
+ }
24
+ finally {
25
+ spinner?.stop();
26
+ }
27
+ }
28
+ function validatePositiveInteger(label) {
29
+ return (value) => {
30
+ const number = Number(value.trim());
31
+ return Number.isInteger(number) && number > 0 ? true : `${label} tiene que ser un numero entero mayor a 0.`;
32
+ };
33
+ }
34
+ /** Pide punto de venta y numero, y lo busca en ARCA. Volver o un comprobante inexistente vuelven a la lista. */
35
+ async function askVoucherByNumber(session, voucherKind, defaultPointOfSale) {
36
+ const pointOfSaleAnswer = await askTextStep('Punto de venta:', {
37
+ defaultValue: String(defaultPointOfSale),
38
+ validate: validatePositiveInteger('El punto de venta'),
39
+ });
40
+ if (pointOfSaleAnswer === BACK) {
41
+ return BACK;
42
+ }
43
+ const numberAnswer = await askTextStep('Numero:', { validate: validatePositiveInteger('El numero') });
44
+ if (numberAnswer === BACK) {
45
+ return BACK;
46
+ }
47
+ const pointOfSale = Number(pointOfSaleAnswer.trim());
48
+ const number = Number(numberAnswer.trim());
49
+ const invoice = await withSpinner('Buscando en ARCA...', () => session.historyGateway.getVoucher(number, pointOfSale, voucherKind.arcaType));
50
+ if (!invoice) {
51
+ writeTerminalOutput(noticePanel(`No existe la ${voucherKind.displayName} N° ${formatVoucherNumber(pointOfSale, number)}.`, 'warning'));
52
+ return BACK;
53
+ }
54
+ return { invoice, pointOfSale };
55
+ }
56
+ /**
57
+ * Elegir un comprobante emitido: los ultimos del punto de venta configurado, con opciones para cargar mas
58
+ * o ingresar el numero a mano (por ejemplo, uno viejo o de otro punto de venta).
59
+ */
60
+ export async function pickInvoice(session, options) {
61
+ const { message, onPick, pointOfSale, voucherKind } = options;
62
+ const { historyGateway } = session;
63
+ // Comprobantes por tanda: los primeros y cada "cargar mas".
64
+ const pageSize = session.runtime.config.comprobantesPorLista ?? RECENT_VOUCHERS_LIMIT;
65
+ const { invoices, lastNumber } = await withSpinner('Buscando en ARCA...', async () => {
66
+ const last = await historyGateway.getLastNumber(pointOfSale, voucherKind.arcaType);
67
+ return {
68
+ invoices: await listVouchersFrom(historyGateway, pointOfSale, voucherKind.arcaType, last, { limit: pageSize }),
69
+ lastNumber: last,
70
+ };
71
+ });
72
+ // Proximo numero a consultar al cargar mas.
73
+ let nextNumber = lastNumber - pageSize;
74
+ let defaultChoice;
75
+ if (invoices.length === 0) {
76
+ writeTerminalOutput(noticePanel(`No hay ${voucherKind.displayName} emitidas en el punto de venta ${pointOfSale}.`, 'warning'));
77
+ }
78
+ // Tanda pedida a ARCA con "cargar mas" mientras la lista sigue en pantalla.
79
+ let loading;
80
+ for (;;) {
81
+ const choices = [];
82
+ // El listado y "cargar mas" van entre lineas punteadas; buscar a mano queda afuera.
83
+ if (invoices.length > 0) {
84
+ // Las filas llegan hasta el final de la linea punteada; el cursor "❯ " ocupa dos columnas.
85
+ const rows = formatVoucherPickerRows(pointOfSale, invoices, COLUMN_SEPARATOR, statusBarWidth() - 2);
86
+ choices.push(listRule(), ...invoices.map((item, index) => ({
87
+ name: rows[index] ?? '',
88
+ // Al elegirla queda solo el numero, no la fila entera.
89
+ short: formatVoucherNumber(pointOfSale, item.number),
90
+ value: item,
91
+ })));
92
+ if (loading) {
93
+ choices.push(new Separator(' '), new Separator(colorize(' Cargando…', 'muted')));
94
+ }
95
+ else if (nextNumber > 0) {
96
+ choices.push(new Separator(' '), { name: '+ Cargar mas…', value: LOAD_MORE });
97
+ }
98
+ choices.push(listRule(), new Separator(' '));
99
+ }
100
+ choices.push({
101
+ description: 'Uno mas viejo o de otro punto de venta',
102
+ name: '# Ingresar el numero a mano…',
103
+ value: BY_NUMBER,
104
+ });
105
+ // +2: el separador y "Volver" que agrega chooseStep.
106
+ const pageSizeOnScreen = fitPageSize(choices.length + 2);
107
+ let answer;
108
+ if (loading) {
109
+ const result = await chooseStepWhileLoading(message, choices, defaultChoice, pageSizeOnScreen, loading);
110
+ loading = undefined;
111
+ if ('loaded' in result) {
112
+ nextNumber -= pageSize;
113
+ // El cursor queda en el primero nuevo; si no vino ninguno, en "cargar mas" o "a mano".
114
+ defaultChoice = result.loaded[0] ?? (nextNumber > 0 ? LOAD_MORE : BY_NUMBER);
115
+ invoices.push(...result.loaded);
116
+ continue;
117
+ }
118
+ // Se eligio otra opcion antes de que terminara la carga: lo que llegue se descarta.
119
+ answer = result.answer;
120
+ }
121
+ else {
122
+ answer = await chooseStep(message, choices, defaultChoice, pageSizeOnScreen);
123
+ }
124
+ if (answer === BACK) {
125
+ return BACK;
126
+ }
127
+ if (answer === LOAD_MORE) {
128
+ // La misma lista se vuelve a dibujar en su lugar, con "Cargando…" en vez del boton.
129
+ eraseLastAnswer();
130
+ loading = listVouchersFrom(historyGateway, pointOfSale, voucherKind.arcaType, nextNumber, { limit: pageSize });
131
+ defaultChoice = invoices.at(-1);
132
+ continue;
133
+ }
134
+ let picked;
135
+ if (answer === BY_NUMBER) {
136
+ const byNumber = await askVoucherByNumber(session, voucherKind, pointOfSale);
137
+ if (byNumber === BACK) {
138
+ defaultChoice = BY_NUMBER;
139
+ continue;
140
+ }
141
+ picked = byNumber;
142
+ }
143
+ else {
144
+ picked = { invoice: answer, pointOfSale };
145
+ }
146
+ if (!onPick) {
147
+ return picked;
148
+ }
149
+ await onPick(picked);
150
+ defaultChoice = answer;
151
+ }
152
+ }
153
+ //# sourceMappingURL=invoice-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoice-picker.js","sourceRoot":"","sources":["../../../src/cli/interactive/invoice-picker.ts"],"names":[],"mappings":"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"}
@@ -3,16 +3,22 @@ import type { VoucherKindDefinition } from '../../modules/billing/billing.types'
3
3
  import { type WizardStep } from '../../modules/interactive/wizard';
4
4
  import { type IssuedVoucher } from '../../modules/vouchers/voucher-history';
5
5
  import { type InteractiveSession } from './session';
6
+ export type NoteKind = 'credito' | 'debito';
6
7
  export interface NoteState {
7
8
  readonly cancellation?: boolean;
8
9
  readonly concept?: BillingConcept;
9
10
  readonly documentNumber?: number;
10
11
  readonly documentType?: BillingCommandInput['documentType'];
12
+ /** Anula la factura entera: la nota copia exento y no gravado. */
13
+ readonly annulsTotal?: boolean;
11
14
  readonly invoice?: IssuedVoucher;
12
15
  readonly invoiceKind?: VoucherKindDefinition;
16
+ /** Punto de venta de la factura asociada; ingresada a mano puede no ser el configurado. */
17
+ readonly invoicePointOfSale?: number;
13
18
  readonly ivaCondition?: BillingCommandInput['ivaCondition'];
14
19
  readonly ivaRate?: BillingCommandInput['ivaRate'];
15
- readonly kind?: 'credito' | 'debito';
20
+ /** Credito o debito: viene del menu principal. */
21
+ readonly kind?: NoteKind;
16
22
  readonly periodFrom?: string;
17
23
  readonly periodTo?: string;
18
24
  /** Sobre una factura de la lista o sobre un periodo (solo notas comunes). */
@@ -23,4 +29,4 @@ export interface NoteState {
23
29
  export declare function noteSteps(session: InteractiveSession, pointOfSale: number): Array<WizardStep<NoteState>>;
24
30
  /** Arma la entrada del CLI con lo que respondio el usuario. */
25
31
  export declare function buildNoteInput(state: NoteState, session: InteractiveSession, pointOfSale: number): BillingCommandInput;
26
- export declare function runNoteFlow(session: InteractiveSession): Promise<void>;
32
+ export declare function runNoteFlow(session: InteractiveSession, kind: NoteKind): Promise<void>;
@@ -3,11 +3,11 @@ import { formatMoneyLabel } from '../../modules/billing/billing.labels.js';
3
3
  import { billingCommandSchema, } from '../../modules/billing/billing.schemas.js';
4
4
  import { parseAmountInput } from '../../modules/interactive/amount-input.js';
5
5
  import { conceptChoices, invoiceKindChoices, ivaConditionChoices, ivaRateChoices, noteKindChoices, receiverChoices, } from '../../modules/interactive/choices.js';
6
+ import { copyInvoiceAmounts } from '../../modules/interactive/invoice-copy.js';
6
7
  import { BACK, runWizard } from '../../modules/interactive/wizard.js';
7
- import { inferIvaRate, listRecentVouchers, resolveDocumentType, } from '../../modules/vouchers/voucher-history.js';
8
- import { formatVoucherSummary } from '../../modules/vouchers/voucher-history.presenter.js';
8
+ import { resolveDocumentType } from '../../modules/vouchers/voucher-history.js';
9
9
  import { noticePanel, writeTerminalOutput } from '../../ui/index.js';
10
- import { startSpinner } from '../spinner.js';
10
+ import { pickInvoice } from './invoice-picker.js';
11
11
  import { askTextStep, chooseStep } from './prompts.js';
12
12
  import { previewAndEmit, requirePointOfSale } from './session.js';
13
13
  import { normalizeDocumentNumber, validateAmount, validateCuit, validateDate, validateDni } from './validators.js';
@@ -20,13 +20,15 @@ const isPeriod = (state) => state.target === 'periodo';
20
20
  async function askNoteAmount(state) {
21
21
  const invoice = state.invoice;
22
22
  const label = state.kind === 'debito' ? 'Monto de la nota de debito:' : 'Monto de la nota de credito:';
23
- if (state.kind === 'credito' && invoice) {
23
+ // Con varias alicuotas o tributos no se puede armar una nota igual a la factura: solo parcial.
24
+ const canAnnulTotal = Boolean(invoice && !copyInvoiceAmounts(invoice, state.invoiceKind?.letter ?? 'c').limitation);
25
+ if (state.kind === 'credito' && invoice && canAnnulTotal) {
24
26
  const scope = await chooseStep('¿Total o parcial?', [
25
27
  { name: `Anular el total (${formatMoneyLabel(invoice.total)})`, value: 'total' },
26
28
  { name: 'Parcial (ingresar monto)', value: 'parcial' },
27
29
  ]);
28
30
  if (scope === BACK || scope === 'total') {
29
- return scope === BACK ? BACK : invoice.total;
31
+ return scope === BACK ? BACK : { annulsTotal: true, totalAmount: invoice.total };
30
32
  }
31
33
  }
32
34
  const answer = await askTextStep(label, {
@@ -40,21 +42,11 @@ async function askNoteAmount(state) {
40
42
  : `No puede superar el total de la factura (${formatMoneyLabel(invoice.total)}).`;
41
43
  },
42
44
  });
43
- return answer === BACK ? BACK : parseAmountInput(answer);
45
+ return answer === BACK ? BACK : { annulsTotal: false, totalAmount: parseAmountInput(answer) };
44
46
  }
45
47
  /** Pasos del flujo de notas; cada uno se puede deshacer con "Volver". */
46
48
  export function noteSteps(session, pointOfSale) {
47
49
  return [
48
- {
49
- name: 'nota',
50
- run: async () => {
51
- const kind = await chooseStep('¿Que nota queres emitir?', [
52
- { name: 'Nota de credito (descuento, devolucion o anulacion)', value: 'credito' },
53
- { name: 'Nota de debito (cargo adicional)', value: 'debito' },
54
- ]);
55
- return kind === BACK ? BACK : { kind };
56
- },
57
- },
58
50
  {
59
51
  name: 'tipo-factura',
60
52
  run: async () => {
@@ -66,7 +58,11 @@ export function noteSteps(session, pointOfSale) {
66
58
  name: 'asociacion',
67
59
  run: async () => {
68
60
  const target = await chooseStep('¿A que la asociamos?', [
69
- { description: 'Elegis una de las ultimas emitidas', name: 'A una factura', value: 'factura' },
61
+ {
62
+ description: 'Elegis una de las ultimas emitidas o la ingresas a mano',
63
+ name: 'A una factura',
64
+ value: 'factura',
65
+ },
70
66
  {
71
67
  description: 'Por ejemplo, un descuento sobre todo el mes',
72
68
  name: 'A un periodo',
@@ -82,33 +78,33 @@ export function noteSteps(session, pointOfSale) {
82
78
  name: 'factura',
83
79
  run: async (state) => {
84
80
  const invoiceKind = state.invoiceKind;
85
- const spinner = startSpinner('Buscando las ultimas facturas en ARCA...');
86
- const invoices = await listRecentVouchers(session.historyGateway, pointOfSale, invoiceKind.arcaType).finally(() => spinner?.stop());
87
- if (invoices.length === 0) {
88
- writeTerminalOutput(noticePanel(`No hay ${invoiceKind.displayName} emitidas en el punto de venta ${pointOfSale}.`, 'warning'));
89
- return BACK;
90
- }
91
- const invoice = await chooseStep(`¿Sobre que ${invoiceKind.displayName}?`, invoices.map((item) => ({
92
- description: item.cae ? `CAE ${item.cae}` : undefined,
93
- name: formatVoucherSummary(pointOfSale, item),
94
- value: item,
95
- })));
96
- if (invoice === BACK) {
81
+ const picked = await pickInvoice(session, {
82
+ message: `¿Sobre que ${invoiceKind.displayName}?`,
83
+ pointOfSale,
84
+ voucherKind: invoiceKind,
85
+ });
86
+ if (picked === BACK) {
97
87
  return BACK;
98
88
  }
89
+ const { invoice } = picked;
99
90
  const documentType = resolveDocumentType(invoice.documentTypeCode);
100
91
  if (!documentType) {
101
92
  writeTerminalOutput(noticePanel('La factura tiene un tipo de documento que el asistente no soporta. Usa los flags del CLI.', 'warning'));
102
93
  return BACK;
103
94
  }
104
- // La nota hereda de la factura el receptor, el concepto y la alicuota (si se puede deducir).
95
+ const copy = copyInvoiceAmounts(invoice, invoiceKind.letter);
96
+ if (copy.limitation) {
97
+ writeTerminalOutput(noticePanel(`${copy.limitation} La nota solo puede ser parcial; revisa la alicuota.`, 'warning'));
98
+ }
99
+ // La nota hereda de la factura el receptor, el concepto, la moneda y la alicuota (si se puede deducir).
105
100
  return {
106
101
  concept: CONCEPTS_BY_CODE[invoice.concept ?? 2] ?? 'servicios',
107
102
  documentNumber: documentType === 'consumidor-final' ? undefined : invoice.documentNumber,
108
103
  documentType,
109
104
  invoice,
105
+ invoicePointOfSale: picked.pointOfSale,
110
106
  ivaCondition: documentType === 'consumidor-final' ? 'consumidor-final' : undefined,
111
- ivaRate: invoiceKind.letter === 'c' ? undefined : inferIvaRate(invoice.netAmount, invoice.ivaAmount),
107
+ ivaRate: copy.ivaRate,
112
108
  };
113
109
  },
114
110
  skip: isPeriod,
@@ -121,7 +117,7 @@ export function noteSteps(session, pointOfSale) {
121
117
  return BACK;
122
118
  }
123
119
  const periodTo = await askTextStep('Periodo hasta:', { validate: validateDate });
124
- return periodTo === BACK ? BACK : { invoice: undefined, periodFrom, periodTo };
120
+ return periodTo === BACK ? BACK : { invoice: undefined, invoicePointOfSale: undefined, periodFrom, periodTo };
125
121
  },
126
122
  skip: (state) => !isPeriod(state),
127
123
  },
@@ -161,8 +157,8 @@ export function noteSteps(session, pointOfSale) {
161
157
  {
162
158
  name: 'monto',
163
159
  run: async (state) => {
164
- const totalAmount = await askNoteAmount(state);
165
- return totalAmount === BACK ? BACK : { totalAmount };
160
+ const amount = await askNoteAmount(state);
161
+ return amount === BACK ? BACK : amount;
166
162
  },
167
163
  },
168
164
  {
@@ -201,6 +197,8 @@ export function buildNoteInput(state, session, pointOfSale) {
201
197
  const invoiceKind = state.invoiceKind;
202
198
  const noteKind = noteKindChoices(state.kind ?? 'credito', invoiceKind);
203
199
  const invoice = state.invoice;
200
+ // Una nota va en la moneda de su factura; si la anula entera, tambien copia exento y no gravado.
201
+ const copy = !isPeriod(state) && invoice ? copyInvoiceAmounts(invoice, invoiceKind.letter) : undefined;
204
202
  return billingCommandSchema.parse({
205
203
  associatedPeriod: isPeriod(state) ? { desde: state.periodFrom, hasta: state.periodTo } : undefined,
206
204
  associatedVoucher: !isPeriod(state) && invoice
@@ -208,26 +206,30 @@ export function buildNoteInput(state, session, pointOfSale) {
208
206
  cuit: String(session.runtime.context.cuit),
209
207
  fecha: formatArcaDateAsArgentineDate(invoice.date),
210
208
  numero: invoice.number,
211
- puntoVenta: pointOfSale,
209
+ puntoVenta: state.invoicePointOfSale ?? pointOfSale,
212
210
  shortcut: invoiceKind.shortcut,
213
211
  }
214
212
  : undefined,
215
213
  cancellation: state.cancellation ?? false,
216
214
  concept: state.concept,
215
+ currencyCode: copy?.currencyCode,
217
216
  documentNumber: state.documentType === 'consumidor-final' ? undefined : state.documentNumber,
218
217
  documentType: state.documentType,
218
+ exchangeRate: copy?.exchangeRate,
219
+ exemptAmount: state.annulsTotal ? copy?.exemptAmount : undefined,
219
220
  ivaCondition: state.ivaCondition,
220
221
  ivaRate: state.ivaRate === '21' && !session.runtime.config.alicuotaPorDefecto ? undefined : state.ivaRate,
221
222
  shortcut: noteKind.shortcut,
222
223
  totalAmount: state.totalAmount,
224
+ untaxedAmount: state.annulsTotal ? copy?.untaxedAmount : undefined,
223
225
  });
224
226
  }
225
- export async function runNoteFlow(session) {
227
+ export async function runNoteFlow(session, kind) {
226
228
  const pointOfSale = requirePointOfSale(session);
227
229
  if (!pointOfSale) {
228
230
  return;
229
231
  }
230
- const state = await runWizard(noteSteps(session, pointOfSale), {});
232
+ const state = await runWizard(noteSteps(session, pointOfSale), { kind });
231
233
  if (!state) {
232
234
  return;
233
235
  }