fizko-cli 0.2.1 → 0.3.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 (2) hide show
  1. package/dist/index.js +109 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -128,6 +128,22 @@ async function post(path2, data, overrideKey, overrideUrl) {
128
128
  return { status: "ok" };
129
129
  }
130
130
  }
131
+ async function put(path2, data) {
132
+ const { apiKey, baseUrl } = getCredentials();
133
+ const url = `${baseUrl}${path2}`;
134
+ const res = await fetch(url, {
135
+ method: "PUT",
136
+ headers: { "Content-Type": "application/json", "X-API-Key": apiKey },
137
+ body: JSON.stringify(data ?? {})
138
+ });
139
+ const text = await res.text();
140
+ if (res.status >= 400) handleError(res.status, text);
141
+ try {
142
+ return JSON.parse(text);
143
+ } catch {
144
+ return { status: "ok" };
145
+ }
146
+ }
131
147
  async function patch(path2, data) {
132
148
  const { apiKey, baseUrl } = getCredentials();
133
149
  const url = `${baseUrl}${path2}`;
@@ -441,26 +457,41 @@ function registerAccounting(program2) {
441
457
  period: opts.period
442
458
  }));
443
459
  });
444
- cmd.command("obligations").description("Listar obligaciones contables (cuentas por pagar/cobrar).").requiredOption("--company <uuid>", "UUID de la empresa").option("--obligation-type <type>", "Tipo: payable o receivable").option("--status <status>", "Estado: pending, partial, paid, overdue").option("--period <yyyy-mm>", "Per\xEDodo YYYY-MM").option("--limit <n>", "L\xEDmite de resultados", (v) => parseInt(v), 30).option("--offset <n>", "Offset de paginaci\xF3n", (v) => parseInt(v), 0).action(async (opts) => {
445
- output(await get("/api/accounting/obligations/", {
460
+ cmd.command("obligations").description("Listar obligaciones contables (cuentas por pagar/cobrar).").requiredOption("--company <uuid>", "UUID de la empresa").option("--obligation-type <type>", "Tipo: payable | receivable").option("--status <status>", "Estado: pending, partial, paid, overdue").option("--source-document-type <type>", "sales_document | purchase_document | honorarios_receipt | payroll_period | form29").option("--search <text>", "B\xFAsqueda libre (n\xFAmero de documento, contrapartida)").option("--from <yyyy-mm-dd>", "Fecha emisi\xF3n desde").option("--to <yyyy-mm-dd>", "Fecha emisi\xF3n hasta").option("--period <yyyy-mm>", "Per\xEDodo YYYY-MM").option("--conciliado <bool>", "true | false").option("--contabilizado <bool>", "true | false").option("--limit <n>", "L\xEDmite de resultados", (v) => parseInt(v), 30).option("--offset <n>", "Offset de paginaci\xF3n", (v) => parseInt(v), 0).action(async (opts) => {
461
+ const params = {
446
462
  company: opts.company,
447
- obligation_type: opts.obligationType,
448
- status: opts.status,
449
- period: opts.period,
450
463
  limit: opts.limit,
451
464
  offset: opts.offset
452
- }));
465
+ };
466
+ if (opts.obligationType) params["obligation_type"] = opts.obligationType;
467
+ if (opts.status) params["status"] = opts.status;
468
+ if (opts.sourceDocumentType) params["source_document_type"] = opts.sourceDocumentType;
469
+ if (opts.search) params["search"] = opts.search;
470
+ if (opts.from) params["issue_date__gte"] = opts.from;
471
+ if (opts.to) params["issue_date__lte"] = opts.to;
472
+ if (opts.period) params["period"] = opts.period;
473
+ if (opts.conciliado !== void 0) params["conciliado"] = opts.conciliado;
474
+ if (opts.contabilizado !== void 0) params["contabilizado"] = opts.contabilizado;
475
+ output(await get("/api/accounting/obligations/", params));
453
476
  });
454
477
  cmd.command("obligation <obligation_id>").description("Obtener detalle de una obligaci\xF3n.").action(async (id) => {
455
478
  output(await get(`/api/accounting/obligations/${id}/`));
456
479
  });
457
- cmd.command("contabilizar <obligation_id>").description("Contabilizar una obligaci\xF3n. Sin --lines, auto-genera el asiento.").option("--lines <json>", 'L\xEDneas del asiento JSON: [{"account_code":"5101","debit":1000,"credit":0}]').option("--account-code <code>", "C\xF3digo de cuenta (modo legacy)").option("--description <text>", "Descripci\xF3n del asiento").action(async (id, opts) => {
480
+ cmd.command("suggest-lines <obligation_id>").description("Obtener sugerencia de l\xEDneas de asiento para una obligaci\xF3n.").action(async (id) => {
481
+ output(await get(`/api/accounting/obligations/${id}/suggest-lines/`));
482
+ });
483
+ cmd.command("contabilizar <obligation_id>").description("Contabilizar una obligaci\xF3n. Sin --lines, auto-genera el asiento.").option("--lines <json>", 'L\xEDneas del asiento JSON: [{"account_code":"5101","debit":1000,"credit":0}]').option("--account-code <code>", "C\xF3digo de cuenta contrapartida").option("--description <text>", "Descripci\xF3n del asiento").action(async (id, opts) => {
458
484
  const body = {};
459
485
  if (opts.lines) body["lines"] = JSON.parse(opts.lines);
460
486
  if (opts.accountCode) body["account_code"] = opts.accountCode;
461
487
  if (opts.description) body["description"] = opts.description;
462
488
  output(await post(`/api/accounting/obligations/${id}/contabilizar/`, body));
463
489
  });
490
+ cmd.command("update-journal <obligation_id>").description("Editar las l\xEDneas del asiento contable de una obligaci\xF3n.").requiredOption("--lines <json>", 'L\xEDneas JSON: [{"account_code":"5101","debit":1000,"credit":0}]').option("--description <text>", "Descripci\xF3n del asiento").action(async (id, opts) => {
491
+ const body = { lines: JSON.parse(opts.lines) };
492
+ if (opts.description) body["description"] = opts.description;
493
+ output(await put(`/api/accounting/obligations/${id}/update-journal-entry/`, body));
494
+ });
464
495
  cmd.command("descontabilizar <obligation_id>").description("Eliminar el asiento contable de una obligaci\xF3n.").action(async (id) => {
465
496
  output(await post(`/api/accounting/obligations/${id}/descontabilizar/`));
466
497
  });
@@ -472,31 +503,89 @@ function registerAccounting(program2) {
472
503
  contabilizar: opts.contabilizar !== false
473
504
  }));
474
505
  });
506
+ cmd.command("payments <obligation_id>").description("Listar los pagos (abonos) registrados en una obligaci\xF3n.").action(async (id) => {
507
+ output(await get(`/api/accounting/obligations/${id}/payments/`));
508
+ });
509
+ cmd.command("reverse-payment <obligation_id>").description("Revertir un pago (abono) de una obligaci\xF3n.").requiredOption("--payment-id <uuid>", "UUID del pago a revertir").action(async (id, opts) => {
510
+ output(await post(`/api/accounting/obligations/${id}/reverse-payment/`, {
511
+ payment_id: opts.paymentId
512
+ }));
513
+ });
514
+ cmd.command("set-cost-center <obligation_id>").description("Asignar un centro de costo a una obligaci\xF3n.").requiredOption("--cost-center <uuid>", "UUID del centro de costo").action(async (id, opts) => {
515
+ output(await post("/api/accounting/obligations/bulk-set-cost-center/", {
516
+ obligation_ids: [id],
517
+ cost_center_id: opts.costCenter
518
+ }));
519
+ });
520
+ cmd.command("cost-centers").description("Listar centros de costo disponibles.").requiredOption("--company <uuid>", "UUID de la empresa").action(async (opts) => {
521
+ output(await get("/api/accounting/cost-centers/", { company_id: opts.company }));
522
+ });
523
+ cmd.command("sync").description("Sincronizar obligaciones desde los documentos tributarios.").requiredOption("--company <uuid>", "UUID de la empresa").option("--period <yyyy-mm>", "Per\xEDodo YYYY-MM").option("--obligation-type <type>", "payable | receivable").option("--force", "Forzar re-sincronizaci\xF3n aunque ya existan").action(async (opts) => {
524
+ const body = { company_id: opts.company };
525
+ if (opts.period) body["period"] = opts.period;
526
+ if (opts.obligationType) body["obligation_type"] = opts.obligationType;
527
+ if (opts.force) body["force_refresh"] = true;
528
+ output(await post("/api/accounting/obligations/sync", body));
529
+ });
475
530
  }
476
531
 
477
532
  // src/commands/banking.ts
478
533
  function registerBanking(program2) {
479
534
  const cmd = program2.command("banking").description("Movimientos bancarios, clasificaci\xF3n y conciliaci\xF3n.");
480
- cmd.command("movements").description("Listar movimientos bancarios.").requiredOption("--company <uuid>", "UUID de la empresa").option("--status <status>", "Estado: pending, reconciled, matched, split").option("--classification <text>", "Filtrar por clasificaci\xF3n").option("--period <yyyy-mm>", "Filtrar por mes (prefijo YYYY-MM)").option("--limit <n>", "L\xEDmite de resultados", (v) => parseInt(v), 30).option("--offset <n>", "Offset de paginaci\xF3n", (v) => parseInt(v), 0).action(async (opts) => {
535
+ cmd.command("movements").description("Listar movimientos bancarios.").requiredOption("--company <uuid>", "UUID de la empresa").option("--status <status>", "Estado: pending, reconciled, matched, split").option("--classification-status <s>", "classified | unclassified").option("--type <type>", "abonos (cr\xE9ditos) | cargos (d\xE9bitos)").option("--search <text>", "B\xFAsqueda libre en descripci\xF3n y clasificaci\xF3n").option("--from <yyyy-mm-dd>", "Fecha desde").option("--to <yyyy-mm-dd>", "Fecha hasta").option("--period <yyyy-mm>", "Filtrar por mes completo (ej: 2026-01)").option("--bank-account <uuid>", "Filtrar por cuenta bancaria").option("--limit <n>", "L\xEDmite de resultados", (v) => parseInt(v), 30).option("--offset <n>", "Offset de paginaci\xF3n", (v) => parseInt(v), 0).action(async (opts) => {
481
536
  const params = {
482
537
  company: opts.company,
483
- status: opts.status,
484
538
  limit: opts.limit,
485
539
  offset: opts.offset
486
540
  };
487
- if (opts.classification) params["classification__icontains"] = opts.classification;
488
- if (opts.period) params["date__gte"] = `${opts.period}-01`;
541
+ if (opts.status) params["status"] = opts.status;
542
+ if (opts.classificationStatus) params["classification_status"] = opts.classificationStatus;
543
+ if (opts.type) params["type"] = opts.type;
544
+ if (opts.search) params["search"] = opts.search;
545
+ if (opts.bankAccount) params["bank_account"] = opts.bankAccount;
546
+ if (opts.from) params["date__gte"] = opts.from;
547
+ if (opts.to) params["date__lte"] = opts.to;
548
+ if (opts.period) {
549
+ const [y, m] = opts.period.split("-").map(Number);
550
+ params["date__gte"] = `${opts.period}-01`;
551
+ params["date__lte"] = `${opts.period}-${String(new Date(y, m, 0).getDate()).padStart(2, "0")}`;
552
+ }
489
553
  output(await get("/api/accounting/bank-movements/", params));
490
554
  });
491
555
  cmd.command("movement <movement_id>").description("Obtener detalle de un movimiento bancario.").action(async (id) => {
492
556
  output(await get(`/api/accounting/bank-movements/${id}/`));
493
557
  });
494
- cmd.command("classify <movement_id>").description("Clasificar un movimiento bancario.").requiredOption("--classification <text>", "Clasificaci\xF3n (ej: 'Gasto Operacional')").option("--document-type <type>", "Tipo documento (ej: 'Factura')").option("--comment <text>", "Comentario").action(async (id, opts) => {
558
+ cmd.command("classify <movement_id>").description("Clasificar un movimiento bancario.").requiredOption("--classification <text>", "Clasificaci\xF3n (ej: 'Gasto Operacional')").option("--document-type <type>", "Tipo documento (ej: 'Factura')").option("--contact-id <uuid>", "UUID del contacto relacionado").option("--comment <text>", "Comentario").action(async (id, opts) => {
495
559
  const body = { classification: opts.classification };
496
560
  if (opts.documentType) body["document_type"] = opts.documentType;
561
+ if (opts.contactId) body["contact_id"] = opts.contactId;
497
562
  if (opts.comment) body["comment"] = opts.comment;
498
563
  output(await patch(`/api/accounting/bank-movements/${id}/classify/`, body));
499
564
  });
565
+ cmd.command("update <movement_id>").description("Actualizar campos de un movimiento (categor\xEDa, comentario, centro de costo, pin).").option("--category <text>", "Categor\xEDa del movimiento").option("--comment <text>", "Comentario").option("--cost-center <uuid>", "UUID del centro de costo").option("--pin <bool>", "Anclar: true | false").action(async (id, opts) => {
566
+ const body = {};
567
+ if (opts.category !== void 0) body["category"] = opts.category;
568
+ if (opts.comment !== void 0) body["comment"] = opts.comment;
569
+ if (opts.costCenter !== void 0) body["cost_center"] = opts.costCenter;
570
+ if (opts.pin !== void 0) body["pinned"] = opts.pin === "true";
571
+ output(await patch(`/api/accounting/bank-movements/${id}/`, body));
572
+ });
573
+ cmd.command("bulk-classify").description("Clasificar m\xFAltiples movimientos a la vez.").requiredOption("--company <uuid>", "UUID de la empresa").requiredOption("--movement-ids <uuids>", "UUIDs separados por coma").requiredOption("--classification <text>", "Clasificaci\xF3n a aplicar").action(async (opts) => {
574
+ const ids = opts.movementIds.split(",").map((s) => s.trim());
575
+ output(await post("/api/accounting/bank-movements/bulk_classify/", {
576
+ movement_ids: ids,
577
+ classification: opts.classification
578
+ }));
579
+ });
580
+ cmd.command("split <movement_id>").description("Dividir un movimiento en sub-movimientos (los montos deben sumar el total).").requiredOption(
581
+ "--splits <json>",
582
+ 'Array JSON: [{"amount":1000,"description":"texto"},...]'
583
+ ).action(async (id, opts) => {
584
+ output(await post("/api/accounting/movement-splits/", {
585
+ original_movement_id: id,
586
+ splits: JSON.parse(opts.splits)
587
+ }));
588
+ });
500
589
  cmd.command("contabilizar <movement_id>").description("Crear asiento contable para un movimiento bancario.").requiredOption("--account-code <code>", "C\xF3digo de cuenta contrapartida (ej: '5101')").option("--description <text>", "Descripci\xF3n del asiento").action(async (id, opts) => {
501
590
  const body = { account_code: opts.accountCode };
502
591
  if (opts.description) body["description"] = opts.description;
@@ -504,13 +593,18 @@ function registerBanking(program2) {
504
593
  });
505
594
  cmd.command("contabilizar-reconciliaciones <movement_id>").description("Crear un asiento por cada reconciliaci\xF3n del movimiento.").requiredOption(
506
595
  "--entries <json>",
507
- 'Array JSON: [{"reconciliation_id":"UUID","lines":[{"account_code":"5101","debit":1000,"credit":0}],"description":"opcional"}]'
596
+ 'Array JSON: [{"reconciliation_id":"UUID","lines":[{"account_code":"5101","debit":1000,"credit":0}]}]'
508
597
  ).action(async (id, opts) => {
509
598
  output(await post(
510
599
  `/api/accounting/bank-movements/${id}/contabilizar-reconciliaciones/`,
511
600
  { entries: JSON.parse(opts.entries) }
512
601
  ));
513
602
  });
603
+ cmd.command("update-journal <movement_id>").description("Editar las l\xEDneas del asiento contable de un movimiento.").requiredOption("--lines <json>", 'L\xEDneas JSON: [{"account_code":"5101","debit":1000,"credit":0}]').option("--description <text>", "Descripci\xF3n del asiento").action(async (id, opts) => {
604
+ const body = { lines: JSON.parse(opts.lines) };
605
+ if (opts.description) body["description"] = opts.description;
606
+ output(await put(`/api/accounting/bank-movements/${id}/update_journal_entry/`, body));
607
+ });
514
608
  cmd.command("descontabilizar <movement_id>").description("Eliminar el asiento contable de un movimiento bancario.").action(async (id) => {
515
609
  output(await post(`/api/accounting/bank-movements/${id}/descontabilizar/`, {}));
516
610
  });
@@ -523,7 +617,7 @@ function registerBanking(program2) {
523
617
  if (opts.amount !== void 0) body["amount"] = opts.amount;
524
618
  output(await post("/api/accounting/reconciliation/match", body));
525
619
  });
526
- cmd.command("reconcile-multi").description("Conciliar un movimiento con m\xFAltiples obligaciones (divide el monto autom\xE1ticamente).").requiredOption("--movement-id <uuid>", "UUID del movimiento bancario").requiredOption("--obligation-ids <uuids>", "UUIDs de obligaciones separados por coma").option("--notes <text>", "Notas", "").action(async (opts) => {
620
+ cmd.command("reconcile-multi").description("Conciliar un movimiento con m\xFAltiples obligaciones.").requiredOption("--movement-id <uuid>", "UUID del movimiento bancario").requiredOption("--obligation-ids <uuids>", "UUIDs de obligaciones separados por coma").option("--notes <text>", "Notas", "").action(async (opts) => {
527
621
  const ids = opts.obligationIds.split(",").map((s) => s.trim());
528
622
  output(await post("/api/accounting/reconciliation/match-multi", {
529
623
  movement_id: opts.movementId,
@@ -531,7 +625,7 @@ function registerBanking(program2) {
531
625
  notes: opts.notes
532
626
  }));
533
627
  });
534
- cmd.command("unmatch <reconciliation_id>").description("Deshacer una conciliaci\xF3n (unmatch).").action(async (id) => {
628
+ cmd.command("unmatch <reconciliation_id>").description("Deshacer una conciliaci\xF3n.").action(async (id) => {
535
629
  output(await post("/api/accounting/reconciliation/unmatch", { reconciliation_id: id }));
536
630
  });
537
631
  cmd.command("list-reconciliations").description("Listar conciliaciones completadas.").requiredOption("--company <uuid>", "UUID de la empresa").option("--period <yyyy-mm>", "Per\xEDodo YYYY-MM").option("--limit <n>", "L\xEDmite de resultados", (v) => parseInt(v), 30).option("--offset <n>", "Offset de paginaci\xF3n", (v) => parseInt(v), 0).action(async (opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fizko-cli",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "CLI para consultar datos tributarios y contables desde la API de Fizko",
5
5
  "license": "MIT",
6
6
  "author": "Akashi Labs <hello@fizko.ai>",