@pimia/sdk 0.12.0 → 0.14.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.
package/dist/api.d.ts CHANGED
@@ -3751,6 +3751,37 @@ export interface paths {
3751
3751
  patch?: never;
3752
3752
  trace?: never;
3753
3753
  };
3754
+ "/received-invoices/{id}/mark-goods-received": {
3755
+ parameters: {
3756
+ query?: never;
3757
+ header?: never;
3758
+ path?: never;
3759
+ cookie?: never;
3760
+ };
3761
+ get?: never;
3762
+ put?: never;
3763
+ /**
3764
+ * Marca la mercancía de la factura recibida como RECIBIDA y suma sus líneas
3765
+ * al almacén — el espejo exacto del `mark-delivered` del albarán de venta
3766
+ * (estudio de stock, decisión S3)
3767
+ * @description Es una acción explícita y no el alta de la factura a propósito: el OCR
3768
+ * crea borradores que se corrigen, y un borrador no es mercancía en la
3769
+ * estantería. El candado es `stock_added_at` —un instante, como el
3770
+ * `stock_deducted_at` del albarán (#473)— y hace la acción idempotente:
3771
+ * la segunda llamada es un 422, no una segunda suma.
3772
+ *
3773
+ * Reglas espejo del albarán, también a propósito: solo mueven almacén las
3774
+ * líneas con `item_id`, y un artículo con `opening_stock` NULL («nunca ha
3775
+ * llevado stock») no se estrena por una compra — se estrena en su ficha o
3776
+ * con un ajuste, que son los gestos que significan «declaro existencias».
3777
+ */
3778
+ post: operations["receivedInvoices.markGoodsReceived"];
3779
+ delete?: never;
3780
+ options?: never;
3781
+ head?: never;
3782
+ patch?: never;
3783
+ trace?: never;
3784
+ };
3754
3785
  "/banking/transactions": {
3755
3786
  parameters: {
3756
3787
  query?: never;
@@ -4566,6 +4597,60 @@ export interface paths {
4566
4597
  patch?: never;
4567
4598
  trace?: never;
4568
4599
  };
4600
+ "/items/{item}/stock-adjustments": {
4601
+ parameters: {
4602
+ query?: never;
4603
+ header?: never;
4604
+ path?: never;
4605
+ cookie?: never;
4606
+ };
4607
+ get?: never;
4608
+ put?: never;
4609
+ /** Ajusta las existencias de un artículo y devuelve el asiento */
4610
+ post: operations["item.stockAdjustments"];
4611
+ delete?: never;
4612
+ options?: never;
4613
+ head?: never;
4614
+ patch?: never;
4615
+ trace?: never;
4616
+ };
4617
+ "/stock-movements": {
4618
+ parameters: {
4619
+ query?: never;
4620
+ header?: never;
4621
+ path?: never;
4622
+ cookie?: never;
4623
+ };
4624
+ /** Los movimientos de stock de la empresa, del más nuevo al más viejo */
4625
+ get: operations["stockMovements.index"];
4626
+ put?: never;
4627
+ post?: never;
4628
+ delete?: never;
4629
+ options?: never;
4630
+ head?: never;
4631
+ patch?: never;
4632
+ trace?: never;
4633
+ };
4634
+ "/items/{item}/stock-movements": {
4635
+ parameters: {
4636
+ query?: never;
4637
+ header?: never;
4638
+ path?: never;
4639
+ cookie?: never;
4640
+ };
4641
+ /**
4642
+ * Los movimientos de stock de UN artículo — la pestaña «Movimientos» de su
4643
+ * ficha, la que responde «¿por qué tengo 47?»
4644
+ */
4645
+ get: operations["stockMovements.forItem"];
4646
+ put?: never;
4647
+ post?: never;
4648
+ delete?: never;
4649
+ options?: never;
4650
+ head?: never;
4651
+ patch?: never;
4652
+ trace?: never;
4653
+ };
4569
4654
  "/store/modules": {
4570
4655
  parameters: {
4571
4656
  query?: never;
@@ -5656,6 +5741,79 @@ export interface paths {
5656
5741
  patch?: never;
5657
5742
  trace?: never;
5658
5743
  };
5744
+ "/warehouses/{warehouse}/stock": {
5745
+ parameters: {
5746
+ query?: never;
5747
+ header?: never;
5748
+ path?: never;
5749
+ cookie?: never;
5750
+ };
5751
+ /**
5752
+ * Las existencias de UN almacén, artículo a artículo
5753
+ * @description La pregunta que la dimensión vino a contestar: «¿cuántos me quedan en la
5754
+ * tienda?». Sale de `item_warehouse_stock`, que es el reparto del contador
5755
+ * global y no una segunda cuenta: la suma por artículo de todos los
5756
+ * almacenes es exactamente `items.opening_stock`.
5757
+ */
5758
+ get: operations["warehouses.stock"];
5759
+ put?: never;
5760
+ post?: never;
5761
+ delete?: never;
5762
+ options?: never;
5763
+ head?: never;
5764
+ patch?: never;
5765
+ trace?: never;
5766
+ };
5767
+ "/warehouses": {
5768
+ parameters: {
5769
+ query?: never;
5770
+ header?: never;
5771
+ path?: never;
5772
+ cookie?: never;
5773
+ };
5774
+ /** Los almacenes de la empresa */
5775
+ get: operations["warehouses.index"];
5776
+ put?: never;
5777
+ /** Da de alta un almacén */
5778
+ post: operations["warehouses.store"];
5779
+ delete?: never;
5780
+ options?: never;
5781
+ head?: never;
5782
+ patch?: never;
5783
+ trace?: never;
5784
+ };
5785
+ "/warehouses/{warehouse}": {
5786
+ parameters: {
5787
+ query?: never;
5788
+ header?: never;
5789
+ path?: never;
5790
+ cookie?: never;
5791
+ };
5792
+ get: operations["warehouses.show"];
5793
+ /**
5794
+ * Edita un almacén
5795
+ * @description ⚠️ El por defecto no se puede APAGAR desde aquí: se cambia encendiendo
5796
+ * otro, que apaga este en la misma transacción. Un `is_default: false`
5797
+ * sobre el único que lo tiene dejaría a la empresa sin sitio donde anotar
5798
+ * lo que no elige, y el 422 lo dice en vez de aceptarlo y romperse luego.
5799
+ */
5800
+ put: operations["warehouses.update"];
5801
+ post?: never;
5802
+ /**
5803
+ * Borra un almacén VACÍO y sin historia
5804
+ * @description Tres negativas, y las tres con su código: el por defecto no se borra
5805
+ * (`default_warehouse_required`), uno con asientos tampoco
5806
+ * (`stock_movements_attached` — el asiento lo nombra, y la historia del
5807
+ * almacén es lo que hace de fiar el saldo), y uno con existencias, menos
5808
+ * (`stock_attached`: borrarlo evaporaría un saldo que sí está en el
5809
+ * contador global). Para el que ya no se usa está `is_active: false`.
5810
+ */
5811
+ delete: operations["warehouses.destroy"];
5812
+ options?: never;
5813
+ head?: never;
5814
+ patch?: never;
5815
+ trace?: never;
5816
+ };
5659
5817
  "/settings/webhooks": {
5660
5818
  parameters: {
5661
5819
  query?: never;
@@ -6679,6 +6837,22 @@ export interface components {
6679
6837
  delivery_note_number: string | null;
6680
6838
  delivery_note_date: string;
6681
6839
  status: string;
6840
+ /**
6841
+ * Format: date-time
6842
+ * @description Cuándo movió el almacén este albarán (NULL = aún no). El #473 lo
6843
+ * creó sin publicarlo y los clientes lo INFERÍAN del estado — que
6844
+ * es justo lo que `convertToInvoice` rompe al pisar `DELIVERED`
6845
+ * con `INVOICED`. Con el libro (estudio de stock, S1) deja de ser
6846
+ * contabilidad interna: es lo que la pantalla del albarán necesita
6847
+ * para contar lo que hizo.
6848
+ */
6849
+ stock_deducted_at: string | null;
6850
+ /**
6851
+ * @description DE DÓNDE se entrega (N2). NULL = del almacén por defecto, que se
6852
+ * resuelve al entregar y no al guardar: cambiar el por defecto no
6853
+ * reescribe la intención de un albarán viejo.
6854
+ */
6855
+ warehouse_id: number | null;
6682
6856
  sub_total: number;
6683
6857
  total: number;
6684
6858
  tax: number;
@@ -7895,6 +8069,12 @@ export interface components {
7895
8069
  notes: string | null;
7896
8070
  price: number;
7897
8071
  purchase_price: number | null;
8072
+ /**
8073
+ * @description Coste medio ponderado en céntimos (S8, informativo): lo
8074
+ * recalcula cada compra recibida; NULL = aún no hay entradas con
8075
+ * coste anotadas.
8076
+ */
8077
+ average_cost_cents: number | null;
7898
8078
  default_discount: number;
7899
8079
  unit_id: number | null;
7900
8080
  company_id: number | null;
@@ -7931,6 +8111,7 @@ export interface components {
7931
8111
  description: string | null;
7932
8112
  price: number;
7933
8113
  purchase_price: number | null;
8114
+ average_cost_cents: number | null;
7934
8115
  default_discount: number;
7935
8116
  category_id: number | null;
7936
8117
  category?: {
@@ -7969,6 +8150,13 @@ export interface components {
7969
8150
  type: string | null;
7970
8151
  }[];
7971
8152
  };
8153
+ /** ItemWarehouseStockResource */
8154
+ ItemWarehouseStockResource: {
8155
+ item_id: number;
8156
+ item_name: string;
8157
+ warehouse_id: number;
8158
+ quantity: number;
8159
+ };
7972
8160
  /** ItemsRequest */
7973
8161
  ItemsRequest: {
7974
8162
  name: string;
@@ -7991,11 +8179,19 @@ export interface components {
7991
8179
  description?: string | null;
7992
8180
  notes?: string | null;
7993
8181
  is_active?: boolean | null;
8182
+ /**
8183
+ * @description Saldo de existencias del artículo. Pese al nombre NO es el
8184
+ * inicial: es el contador vivo que mueven albaranes, facturas,
8185
+ * compras y ajustes (el detalle, en `GET /items/{item}/stock-movements`).
8186
+ * En el alta se guarda 0 si no llega; en la actualización se
8187
+ * conserva el que había. Escribirlo aquí pisa el saldo (queda
8188
+ * anotado como `manual_edit`); para corregir con motivo está
8189
+ * `POST /items/{item}/stock-adjustments`.
8190
+ */
8191
+ opening_stock?: number | null;
7994
8192
  stock_alert_qty?: number | null;
7995
8193
  allow_sale_without_stock?: boolean | null;
7996
8194
  purchase_tax_type_id?: number | null;
7997
- /** @description Existencias iniciales del artículo. En el alta se guarda 0 si no llega; en la actualización se conserva el valor que ya tenía. */
7998
- opening_stock?: number | null;
7999
8195
  };
8000
8196
  /** LeadActivity */
8001
8197
  LeadActivity: {
@@ -8468,6 +8664,13 @@ export interface components {
8468
8664
  tax?: number | null;
8469
8665
  total?: number | null;
8470
8666
  }[];
8667
+ /**
8668
+ * @description DÓNDE entra la mercancía (N2). Opcional: sin él, el almacén por
8669
+ * defecto de la empresa. Se lee al marcar la mercancía como
8670
+ * recibida —no al guardar la factura—, porque el OCR crea
8671
+ * borradores que se corrigen antes de que llegue nada.
8672
+ */
8673
+ warehouse_id?: number | null;
8471
8674
  };
8472
8675
  /** ReceivedInvoiceResource */
8473
8676
  ReceivedInvoiceResource: {
@@ -8477,6 +8680,19 @@ export interface components {
8477
8680
  received_invoice_number: string | null;
8478
8681
  reference_number: string | null;
8479
8682
  status: string;
8683
+ /**
8684
+ * Format: date-time
8685
+ * @description Cuándo se sumó la mercancía al almacén (mark-goods-received);
8686
+ * NULL si aún no. Se publica —al contrario que en su día el
8687
+ * `stock_deducted_at` del albarán— porque es lo que permite a un
8688
+ * cliente pintar el botón «Mercancía recibida» solo cuando toca.
8689
+ */
8690
+ stock_added_at: string | null;
8691
+ /**
8692
+ * @description DÓNDE entra la mercancía (N2). NULL = el almacén por defecto,
8693
+ * resuelto al marcarla recibida.
8694
+ */
8695
+ warehouse_id: number | null;
8480
8696
  paid_status: string;
8481
8697
  tax_per_item: string | null;
8482
8698
  discount_per_item: string | null;
@@ -8751,7 +8967,7 @@ export interface components {
8751
8967
  * ningún permiso es una operación legítima, y `required` la
8752
8968
  * prohibiría (un array vacío no pasa `required`).
8753
8969
  */
8754
- abilities: ("dashboard" | "view-customer" | "create-customer" | "edit-customer" | "delete-customer" | "view-estimate" | "create-estimate" | "edit-estimate" | "delete-estimate" | "send-estimate" | "view-invoice" | "create-invoice" | "edit-invoice" | "delete-invoice" | "send-invoice" | "view-recurring-invoice" | "create-recurring-invoice" | "edit-recurring-invoice" | "delete-recurring-invoice" | "view-payment" | "create-payment" | "edit-payment" | "delete-payment" | "send-payment" | "view-expense" | "create-expense" | "edit-expense" | "delete-expense" | "view-delivery-note" | "create-delivery-note" | "edit-delivery-note" | "delete-delivery-note" | "view-item" | "create-item" | "edit-item" | "delete-item" | "view-lead" | "create-lead" | "edit-lead" | "delete-lead" | "convert-lead" | "view-contact" | "create-contact" | "edit-contact" | "delete-contact" | "view-project" | "create-project" | "edit-project" | "delete-project" | "view-task" | "create-task" | "edit-task" | "delete-task" | "view-own-task" | "edit-own-task" | "view-time-entry" | "create-time-entry" | "edit-time-entry" | "delete-time-entry" | "view-own-time-entry" | "create-own-time-entry" | "edit-own-time-entry" | "delete-own-time-entry" | "view-tax-type" | "create-tax-type" | "edit-tax-type" | "delete-tax-type" | "view-custom-field" | "create-custom-field" | "edit-custom-field" | "delete-custom-field" | "view-role" | "create-role" | "edit-role" | "delete-role" | "view-financial-reports" | "view-all-notes" | "manage-all-notes" | "time_clock.punch" | "time_clock.view_own" | "time_clock.view_team" | "time_clock.correct" | "absence.request" | "absence.approve" | "report.download_legal" | "view-employee" | "create-employee" | "edit-employee" | "delete-employee" | "view-work-schedule" | "manage-work-schedule" | "view-work-calendar" | "manage-work-calendar" | "pos.operate" | "pos.supervise" | "pos.void" | "pos.discount_high" | "pos.cash_movement" | "pos.return" | "pos.admin" | "pos.report" | "view-appointment" | "create-appointment" | "edit-appointment" | "delete-appointment" | "view-contract" | "create-contract" | "edit-contract" | "delete-contract")[];
8970
+ abilities: ("dashboard" | "view-customer" | "create-customer" | "edit-customer" | "delete-customer" | "view-estimate" | "create-estimate" | "edit-estimate" | "delete-estimate" | "send-estimate" | "view-invoice" | "create-invoice" | "edit-invoice" | "delete-invoice" | "send-invoice" | "view-recurring-invoice" | "create-recurring-invoice" | "edit-recurring-invoice" | "delete-recurring-invoice" | "view-payment" | "create-payment" | "edit-payment" | "delete-payment" | "send-payment" | "view-expense" | "create-expense" | "edit-expense" | "delete-expense" | "view-delivery-note" | "create-delivery-note" | "edit-delivery-note" | "delete-delivery-note" | "view-item" | "create-item" | "edit-item" | "delete-item" | "view-lead" | "create-lead" | "edit-lead" | "delete-lead" | "convert-lead" | "view-contact" | "create-contact" | "edit-contact" | "delete-contact" | "view-project" | "create-project" | "edit-project" | "delete-project" | "view-task" | "create-task" | "edit-task" | "delete-task" | "view-own-task" | "edit-own-task" | "view-time-entry" | "create-time-entry" | "edit-time-entry" | "delete-time-entry" | "view-own-time-entry" | "create-own-time-entry" | "edit-own-time-entry" | "delete-own-time-entry" | "view-tax-type" | "create-tax-type" | "edit-tax-type" | "delete-tax-type" | "view-custom-field" | "create-custom-field" | "edit-custom-field" | "delete-custom-field" | "view-role" | "create-role" | "edit-role" | "delete-role" | "view-financial-reports" | "view-all-notes" | "manage-all-notes" | "time_clock.punch" | "time_clock.view_own" | "time_clock.view_team" | "time_clock.correct" | "absence.request" | "absence.approve" | "report.download_legal" | "view-employee" | "create-employee" | "edit-employee" | "delete-employee" | "view-work-schedule" | "manage-work-schedule" | "view-work-calendar" | "manage-work-calendar" | "pos.operate" | "pos.supervise" | "pos.void" | "pos.discount_high" | "pos.cash_movement" | "pos.return" | "pos.admin" | "pos.report" | "view-appointment" | "create-appointment" | "edit-appointment" | "delete-appointment" | "view-contract" | "create-contract" | "edit-contract" | "delete-contract" | "view-warehouse" | "create-warehouse" | "edit-warehouse" | "delete-warehouse")[];
8755
8971
  };
8756
8972
  /**
8757
8973
  * RoleRequest
@@ -8776,7 +8992,7 @@ export interface components {
8776
8992
  name: string;
8777
8993
  abilities?: {
8778
8994
  /** @enum {string} */
8779
- ability: "dashboard" | "view-customer" | "create-customer" | "edit-customer" | "delete-customer" | "view-estimate" | "create-estimate" | "edit-estimate" | "delete-estimate" | "send-estimate" | "view-invoice" | "create-invoice" | "edit-invoice" | "delete-invoice" | "send-invoice" | "view-recurring-invoice" | "create-recurring-invoice" | "edit-recurring-invoice" | "delete-recurring-invoice" | "view-payment" | "create-payment" | "edit-payment" | "delete-payment" | "send-payment" | "view-expense" | "create-expense" | "edit-expense" | "delete-expense" | "view-delivery-note" | "create-delivery-note" | "edit-delivery-note" | "delete-delivery-note" | "view-item" | "create-item" | "edit-item" | "delete-item" | "view-lead" | "create-lead" | "edit-lead" | "delete-lead" | "convert-lead" | "view-contact" | "create-contact" | "edit-contact" | "delete-contact" | "view-project" | "create-project" | "edit-project" | "delete-project" | "view-task" | "create-task" | "edit-task" | "delete-task" | "view-own-task" | "edit-own-task" | "view-time-entry" | "create-time-entry" | "edit-time-entry" | "delete-time-entry" | "view-own-time-entry" | "create-own-time-entry" | "edit-own-time-entry" | "delete-own-time-entry" | "view-tax-type" | "create-tax-type" | "edit-tax-type" | "delete-tax-type" | "view-custom-field" | "create-custom-field" | "edit-custom-field" | "delete-custom-field" | "view-role" | "create-role" | "edit-role" | "delete-role" | "view-financial-reports" | "view-all-notes" | "manage-all-notes" | "time_clock.punch" | "time_clock.view_own" | "time_clock.view_team" | "time_clock.correct" | "absence.request" | "absence.approve" | "report.download_legal" | "view-employee" | "create-employee" | "edit-employee" | "delete-employee" | "view-work-schedule" | "manage-work-schedule" | "view-work-calendar" | "manage-work-calendar" | "pos.operate" | "pos.supervise" | "pos.void" | "pos.discount_high" | "pos.cash_movement" | "pos.return" | "pos.admin" | "pos.report" | "view-appointment" | "create-appointment" | "edit-appointment" | "delete-appointment" | "view-contract" | "create-contract" | "edit-contract" | "delete-contract";
8995
+ ability: "dashboard" | "view-customer" | "create-customer" | "edit-customer" | "delete-customer" | "view-estimate" | "create-estimate" | "edit-estimate" | "delete-estimate" | "send-estimate" | "view-invoice" | "create-invoice" | "edit-invoice" | "delete-invoice" | "send-invoice" | "view-recurring-invoice" | "create-recurring-invoice" | "edit-recurring-invoice" | "delete-recurring-invoice" | "view-payment" | "create-payment" | "edit-payment" | "delete-payment" | "send-payment" | "view-expense" | "create-expense" | "edit-expense" | "delete-expense" | "view-delivery-note" | "create-delivery-note" | "edit-delivery-note" | "delete-delivery-note" | "view-item" | "create-item" | "edit-item" | "delete-item" | "view-lead" | "create-lead" | "edit-lead" | "delete-lead" | "convert-lead" | "view-contact" | "create-contact" | "edit-contact" | "delete-contact" | "view-project" | "create-project" | "edit-project" | "delete-project" | "view-task" | "create-task" | "edit-task" | "delete-task" | "view-own-task" | "edit-own-task" | "view-time-entry" | "create-time-entry" | "edit-time-entry" | "delete-time-entry" | "view-own-time-entry" | "create-own-time-entry" | "edit-own-time-entry" | "delete-own-time-entry" | "view-tax-type" | "create-tax-type" | "edit-tax-type" | "delete-tax-type" | "view-custom-field" | "create-custom-field" | "edit-custom-field" | "delete-custom-field" | "view-role" | "create-role" | "edit-role" | "delete-role" | "view-financial-reports" | "view-all-notes" | "manage-all-notes" | "time_clock.punch" | "time_clock.view_own" | "time_clock.view_team" | "time_clock.correct" | "absence.request" | "absence.approve" | "report.download_legal" | "view-employee" | "create-employee" | "edit-employee" | "delete-employee" | "view-work-schedule" | "manage-work-schedule" | "view-work-calendar" | "manage-work-calendar" | "pos.operate" | "pos.supervise" | "pos.void" | "pos.discount_high" | "pos.cash_movement" | "pos.return" | "pos.admin" | "pos.report" | "view-appointment" | "create-appointment" | "edit-appointment" | "delete-appointment" | "view-contract" | "create-contract" | "edit-contract" | "delete-contract" | "view-warehouse" | "create-warehouse" | "edit-warehouse" | "delete-warehouse";
8780
8996
  }[] | null;
8781
8997
  };
8782
8998
  /** RoleResource */
@@ -8855,6 +9071,70 @@ export interface components {
8855
9071
  SettingRequest: {
8856
9072
  settings: string;
8857
9073
  };
9074
+ /** StockAdjustmentRequest */
9075
+ StockAdjustmentRequest: {
9076
+ /**
9077
+ * @description Cantidad FIRMADA que se aplica al contador: positiva repone,
9078
+ * negativa retira. Decimal a propósito (litros, kg); el contador
9079
+ * redondea y el asiento guarda la cantidad exacta.
9080
+ */
9081
+ quantity: number;
9082
+ /**
9083
+ * @description El motivo es obligatorio: un ajuste sin porqué es el contador
9084
+ * pisado de siempre, que es justo lo que el libro viene a retirar.
9085
+ */
9086
+ note: string;
9087
+ /**
9088
+ * @description DÓNDE (N2). Opcional: sin él, el ajuste cae en el almacén por
9089
+ * defecto de la empresa — que es lo que hacía antes de que la
9090
+ * dimensión existiera. Se valida contra los almacenes de ESTA
9091
+ * empresa: un id ajeno no es un error de tipo, es un intento de
9092
+ * escribir en el almacén de otro.
9093
+ */
9094
+ warehouse_id?: number | null;
9095
+ };
9096
+ /** StockMovementResource */
9097
+ StockMovementResource: {
9098
+ id: number;
9099
+ item_id: number | null;
9100
+ /**
9101
+ * @description El nombre del artículo, para que el índice GLOBAL del libro sea
9102
+ * legible sin cruzarlo con el catálogo en el cliente. NULL cuando
9103
+ * el artículo ya no existe (`item_id` es nullOnDelete: el asiento
9104
+ * sobrevive al artículo y su nombre no — el cliente lo enseña como
9105
+ * «artículo borrado», que es la verdad). Los dos índices lo cargan
9106
+ * con `with('item:id,name')`: sin eso sería un N+1 por fila.
9107
+ */
9108
+ item_name: string | null;
9109
+ /**
9110
+ * @description DÓNDE pasó (N2). Los asientos anteriores a la dimensión están
9111
+ * todos en el «Principal» que estrenó la migración: es la única
9112
+ * respuesta verdadera, porque nadie declaró jamás dónde estaban.
9113
+ * NULL solo si el almacén desapareció (`nullOnDelete`), igual que
9114
+ * `item_name` — y con el mismo eager load, `warehouse:id,name`.
9115
+ */
9116
+ warehouse_id: number | null;
9117
+ warehouse_name: string | null;
9118
+ /**
9119
+ * @description Cantidad FIRMADA que trajo la causa (decimal: hay artículos en
9120
+ * litros y kg). El contador redondea; la diferencia se ve en la
9121
+ * cadena de `balance_after`.
9122
+ */
9123
+ quantity: number;
9124
+ balance_after: number;
9125
+ /**
9126
+ * @description El coste unitario de una ENTRADA, en céntimos (S8). NULL en las
9127
+ * salidas y en las entradas sin coste conocido.
9128
+ */
9129
+ unit_cost_cents: number | null;
9130
+ reason: string;
9131
+ document_type: string | null;
9132
+ document_id: number | null;
9133
+ note: string | null;
9134
+ creator_id: number | null;
9135
+ /** Format: date-time */
9136
+ created_at: string;
9137
+ };
8858
9138
  /**
8859
9139
  * StoreApprovalRequest
8860
9140
  * @description POST /api/v1/approvals (paso 2, plataforma de integradores) — una app de
@@ -9392,6 +9672,37 @@ export interface components {
9392
9672
  role: string | null;
9393
9673
  }[];
9394
9674
  };
9675
+ /** WarehouseRequest */
9676
+ WarehouseRequest: {
9677
+ name: string;
9678
+ code?: string | null;
9679
+ address?: string | null;
9680
+ is_default?: boolean | null;
9681
+ is_active?: boolean | null;
9682
+ };
9683
+ /** WarehouseResource */
9684
+ WarehouseResource: {
9685
+ id: number;
9686
+ name: string;
9687
+ code: string | null;
9688
+ address: string | null;
9689
+ /**
9690
+ * @description Exactamente uno por empresa lo lleva puesto: es el que hereda
9691
+ * todo movimiento que no elige almacén, que hoy son casi todos
9692
+ * (solo albarán y recepción preguntan).
9693
+ */
9694
+ is_default: boolean;
9695
+ /**
9696
+ * @description Un almacén con historia no se borra —el asiento lo nombra—: se
9697
+ * desactiva. Desactivado no se ofrece para movimientos nuevos y
9698
+ * sigue explicando los viejos.
9699
+ */
9700
+ is_active: boolean;
9701
+ /** Format: date-time */
9702
+ created_at: string | null;
9703
+ /** Format: date-time */
9704
+ updated_at: string | null;
9705
+ };
9395
9706
  /** WorkCalendarRequest */
9396
9707
  WorkCalendarRequest: {
9397
9708
  name: string;
@@ -12629,6 +12940,12 @@ export interface operations {
12629
12940
  quantity: number;
12630
12941
  price: number;
12631
12942
  }[];
12943
+ /**
12944
+ * @description DE DÓNDE se entrega (N2). Opcional: sin él, el almacén por
12945
+ * defecto. Se valida contra los almacenes de ESTA empresa — un id
12946
+ * ajeno no es un error de tipo, es escribir en el almacén de otro.
12947
+ */
12948
+ warehouse_id?: number | null;
12632
12949
  };
12633
12950
  };
12634
12951
  };
@@ -12691,6 +13008,12 @@ export interface operations {
12691
13008
  quantity: number;
12692
13009
  price: number;
12693
13010
  }[];
13011
+ /**
13012
+ * @description DE DÓNDE se entrega (N2). Opcional: sin él, el almacén por
13013
+ * defecto. Se valida contra los almacenes de ESTA empresa — un id
13014
+ * ajeno no es un error de tipo, es escribir en el almacén de otro.
13015
+ */
13016
+ warehouse_id?: number | null;
12694
13017
  };
12695
13018
  };
12696
13019
  };
@@ -17658,6 +17981,43 @@ export interface operations {
17658
17981
  };
17659
17982
  };
17660
17983
  };
17984
+ "receivedInvoices.markGoodsReceived": {
17985
+ parameters: {
17986
+ query?: never;
17987
+ header?: never;
17988
+ path: {
17989
+ id: string;
17990
+ };
17991
+ cookie?: never;
17992
+ };
17993
+ requestBody?: never;
17994
+ responses: {
17995
+ /** @description `ReceivedInvoiceResource` */
17996
+ 200: {
17997
+ headers: {
17998
+ [name: string]: unknown;
17999
+ };
18000
+ content: {
18001
+ "application/json": {
18002
+ data: components["schemas"]["ReceivedInvoiceResource"];
18003
+ };
18004
+ };
18005
+ };
18006
+ 422: {
18007
+ headers: {
18008
+ [name: string]: unknown;
18009
+ };
18010
+ content: {
18011
+ "application/json": {
18012
+ /** @constant */
18013
+ error: "goods_already_received";
18014
+ /** @constant */
18015
+ message: "La mercancía de esta factura recibida ya se sumó al almacén.";
18016
+ };
18017
+ };
18018
+ };
18019
+ };
18020
+ };
17661
18021
  "reconciliation.transactions": {
17662
18022
  parameters: {
17663
18023
  query?: {
@@ -19175,6 +19535,123 @@ export interface operations {
19175
19535
  };
19176
19536
  };
19177
19537
  };
19538
+ "item.stockAdjustments": {
19539
+ parameters: {
19540
+ query?: never;
19541
+ header?: never;
19542
+ path: {
19543
+ item: string;
19544
+ };
19545
+ cookie?: never;
19546
+ };
19547
+ requestBody: {
19548
+ content: {
19549
+ "application/json": components["schemas"]["StockAdjustmentRequest"];
19550
+ };
19551
+ };
19552
+ responses: {
19553
+ /** @description `StockMovementResource` */
19554
+ 201: {
19555
+ headers: {
19556
+ [name: string]: unknown;
19557
+ };
19558
+ content: {
19559
+ "application/json": {
19560
+ data: components["schemas"]["StockMovementResource"];
19561
+ };
19562
+ };
19563
+ };
19564
+ 403: components["responses"]["AuthorizationException"];
19565
+ 422: components["responses"]["ValidationException"];
19566
+ };
19567
+ };
19568
+ "stockMovements.index": {
19569
+ parameters: {
19570
+ query?: {
19571
+ /** @description Solo los asientos de este artículo. */
19572
+ item_id?: number;
19573
+ /** @description Solo los asientos con este motivo (`initial`, `import`, `manual_edit`, `manual_adjustment`, `purchase`, `sale_invoice`, `delivery_note`, `pos_sale`, `pos_return`). */
19574
+ reason?: string;
19575
+ /** @description Solo los asientos de este almacén. */
19576
+ warehouse_id?: number;
19577
+ /** @description Desde esta fecha (YYYY-MM-DD). */
19578
+ from_date?: string;
19579
+ /** @description Hasta esta fecha (YYYY-MM-DD). */
19580
+ to_date?: string;
19581
+ };
19582
+ header?: never;
19583
+ path?: never;
19584
+ cookie?: never;
19585
+ };
19586
+ requestBody?: never;
19587
+ responses: {
19588
+ /** @description Array of `StockMovementResource` */
19589
+ 200: {
19590
+ headers: {
19591
+ [name: string]: unknown;
19592
+ };
19593
+ content: {
19594
+ "application/json": {
19595
+ data: components["schemas"]["StockMovementResource"][];
19596
+ meta: {
19597
+ stock_movement_total_count: number;
19598
+ /**
19599
+ * @description S8, informativo: lo que vale el almacén hoy, en céntimos —
19600
+ * existencias × coste medio aprendido, con el precio de compra
19601
+ * de la ficha como respaldo cuando aún no hay medio. Los
19602
+ * artículos sin ninguno de los dos cuentan 0: la cifra no se
19603
+ * inventa costes, y por eso puede quedarse corta — nunca
19604
+ * larga. NO es un asiento contable ni una valoración de
19605
+ * cierre (estudio de stock §6).
19606
+ */
19607
+ stock_value_cents: number;
19608
+ };
19609
+ };
19610
+ };
19611
+ };
19612
+ 403: components["responses"]["AuthorizationException"];
19613
+ };
19614
+ };
19615
+ "stockMovements.forItem": {
19616
+ parameters: {
19617
+ query?: never;
19618
+ header?: never;
19619
+ path: {
19620
+ item: string;
19621
+ };
19622
+ cookie?: never;
19623
+ };
19624
+ requestBody?: never;
19625
+ responses: {
19626
+ /** @description Array of `StockMovementResource` */
19627
+ 200: {
19628
+ headers: {
19629
+ [name: string]: unknown;
19630
+ };
19631
+ content: {
19632
+ "application/json": {
19633
+ data: components["schemas"]["StockMovementResource"][];
19634
+ meta: {
19635
+ opening_stock: number | null;
19636
+ /**
19637
+ * @description El reparto del saldo por almacén (N2). Su suma es
19638
+ * exactamente `opening_stock` de arriba — es el mismo número
19639
+ * contado por sitios, no una segunda cuenta. Se sirve entero
19640
+ * (una pyme tiene almacenes de contar con los dedos) y sin
19641
+ * paginar: es cabecera de la pestaña, no listado.
19642
+ */
19643
+ warehouse_stock: {
19644
+ warehouse_id: number;
19645
+ warehouse_name: string;
19646
+ quantity: number;
19647
+ }[];
19648
+ };
19649
+ };
19650
+ };
19651
+ };
19652
+ 403: components["responses"]["AuthorizationException"];
19653
+ };
19654
+ };
19178
19655
  "storeModules.index": {
19179
19656
  parameters: {
19180
19657
  query?: never;
@@ -24230,6 +24707,180 @@ export interface operations {
24230
24707
  422: components["responses"]["ValidationException"];
24231
24708
  };
24232
24709
  };
24710
+ "warehouses.stock": {
24711
+ parameters: {
24712
+ query?: {
24713
+ /** @description Filtra por nombre del artículo. */
24714
+ search?: string;
24715
+ /** @description Solo los artículos con saldo distinto de cero (`1`). */
24716
+ only_with_stock?: boolean;
24717
+ };
24718
+ header?: never;
24719
+ path: {
24720
+ /** @description The warehouse ID */
24721
+ warehouse: number;
24722
+ };
24723
+ cookie?: never;
24724
+ };
24725
+ requestBody?: never;
24726
+ responses: {
24727
+ /** @description Array of `ItemWarehouseStockResource` */
24728
+ 200: {
24729
+ headers: {
24730
+ [name: string]: unknown;
24731
+ };
24732
+ content: {
24733
+ "application/json": {
24734
+ data: components["schemas"]["ItemWarehouseStockResource"][];
24735
+ meta: {
24736
+ warehouse: components["schemas"]["WarehouseResource"];
24737
+ };
24738
+ };
24739
+ };
24740
+ };
24741
+ 403: components["responses"]["AuthorizationException"];
24742
+ 404: components["responses"]["ModelNotFoundException"];
24743
+ };
24744
+ };
24745
+ "warehouses.index": {
24746
+ parameters: {
24747
+ query?: {
24748
+ /** @description Filtra por nombre o código. */
24749
+ search?: string;
24750
+ /** @description Solo los activos (`1`) o solo los desactivados (`0`). */
24751
+ is_active?: boolean;
24752
+ };
24753
+ header?: never;
24754
+ path?: never;
24755
+ cookie?: never;
24756
+ };
24757
+ requestBody?: never;
24758
+ responses: {
24759
+ /** @description Array of `WarehouseResource` */
24760
+ 200: {
24761
+ headers: {
24762
+ [name: string]: unknown;
24763
+ };
24764
+ content: {
24765
+ "application/json": {
24766
+ data: components["schemas"]["WarehouseResource"][];
24767
+ };
24768
+ };
24769
+ };
24770
+ 403: components["responses"]["AuthorizationException"];
24771
+ };
24772
+ };
24773
+ "warehouses.store": {
24774
+ parameters: {
24775
+ query?: never;
24776
+ header?: never;
24777
+ path?: never;
24778
+ cookie?: never;
24779
+ };
24780
+ requestBody: {
24781
+ content: {
24782
+ "application/json": components["schemas"]["WarehouseRequest"];
24783
+ };
24784
+ };
24785
+ responses: {
24786
+ /** @description El recurso recién creado. */
24787
+ 201: {
24788
+ headers: {
24789
+ [name: string]: unknown;
24790
+ };
24791
+ content: {
24792
+ "application/json": 201;
24793
+ };
24794
+ };
24795
+ 403: components["responses"]["AuthorizationException"];
24796
+ 422: components["responses"]["ValidationException"];
24797
+ };
24798
+ };
24799
+ "warehouses.show": {
24800
+ parameters: {
24801
+ query?: never;
24802
+ header?: never;
24803
+ path: {
24804
+ /** @description The warehouse ID */
24805
+ warehouse: number;
24806
+ };
24807
+ cookie?: never;
24808
+ };
24809
+ requestBody?: never;
24810
+ responses: {
24811
+ /** @description `WarehouseResource` */
24812
+ 200: {
24813
+ headers: {
24814
+ [name: string]: unknown;
24815
+ };
24816
+ content: {
24817
+ "application/json": {
24818
+ data: components["schemas"]["WarehouseResource"];
24819
+ };
24820
+ };
24821
+ };
24822
+ 403: components["responses"]["AuthorizationException"];
24823
+ 404: components["responses"]["ModelNotFoundException"];
24824
+ };
24825
+ };
24826
+ "warehouses.update": {
24827
+ parameters: {
24828
+ query?: never;
24829
+ header?: never;
24830
+ path: {
24831
+ /** @description The warehouse ID */
24832
+ warehouse: number;
24833
+ };
24834
+ cookie?: never;
24835
+ };
24836
+ requestBody: {
24837
+ content: {
24838
+ "application/json": components["schemas"]["WarehouseRequest"];
24839
+ };
24840
+ };
24841
+ responses: {
24842
+ /** @description `WarehouseResource` */
24843
+ 200: {
24844
+ headers: {
24845
+ [name: string]: unknown;
24846
+ };
24847
+ content: {
24848
+ "application/json": {
24849
+ data: components["schemas"]["WarehouseResource"];
24850
+ } | string;
24851
+ };
24852
+ };
24853
+ 403: components["responses"]["AuthorizationException"];
24854
+ 404: components["responses"]["ModelNotFoundException"];
24855
+ 422: components["responses"]["ValidationException"];
24856
+ };
24857
+ };
24858
+ "warehouses.destroy": {
24859
+ parameters: {
24860
+ query?: never;
24861
+ header?: never;
24862
+ path: {
24863
+ /** @description The warehouse ID */
24864
+ warehouse: number;
24865
+ };
24866
+ cookie?: never;
24867
+ };
24868
+ requestBody?: never;
24869
+ responses: {
24870
+ 200: {
24871
+ headers: {
24872
+ [name: string]: unknown;
24873
+ };
24874
+ content: {
24875
+ "application/json": {
24876
+ success: string;
24877
+ };
24878
+ };
24879
+ };
24880
+ 403: components["responses"]["AuthorizationException"];
24881
+ 404: components["responses"]["ModelNotFoundException"];
24882
+ };
24883
+ };
24233
24884
  "webhookEndpoints.index": {
24234
24885
  parameters: {
24235
24886
  query?: never;
package/dist/client.d.ts CHANGED
@@ -25,6 +25,10 @@ export type InvoiceResource = Schemas['InvoiceResource'];
25
25
  export type EstimateResource = Schemas['EstimateResource'];
26
26
  /** Contrato de servicio tal y como lo devuelve la API. */
27
27
  export type ContractResource = Schemas['ContractResource'];
28
+ /** Almacén tal y como lo devuelve la API. */
29
+ export type WarehouseResource = Schemas['WarehouseResource'];
30
+ /** El saldo de un artículo EN un almacén. */
31
+ export type ItemWarehouseStockResource = Schemas['ItemWarehouseStockResource'];
28
32
  /** Cuerpo de alta/edición de cliente. Incluye `customFields`. */
29
33
  export type CustomerRequest = Schemas['CustomerRequest'];
30
34
  /** Cuerpo de alta/edición de factura. Incluye `customFields`. */
@@ -36,6 +40,12 @@ export type EstimatesRequest = Schemas['EstimatesRequest'];
36
40
  * vida va por sus acciones (`activate`/`cancel`/`renew`), nunca por el PUT.
37
41
  */
38
42
  export type ContractRequest = Schemas['ContractRequest'];
43
+ /**
44
+ * Cuerpo de alta/edición de almacén. `is_default` se manda como INTENCIÓN
45
+ * («que este sea el de por defecto»): el servidor apaga el anterior en la
46
+ * misma transacción, porque la empresa necesita exactamente uno.
47
+ */
48
+ export type WarehouseRequest = Schemas['WarehouseRequest'];
39
49
  /**
40
50
  * El sobre `{ data: … }` de Laravel para las escrituras que el spec **no
41
51
  * tipa**.
@@ -791,6 +801,66 @@ export declare class PimiaClient {
791
801
  invoices?: components["schemas"]["InvoiceResource"][];
792
802
  }>>;
793
803
  };
804
+ /**
805
+ * Almacenes: la DIMENSIÓN del stock. Exige `items:read` / `items:write` —
806
+ * el almacén cuelga del catálogo que dimensiona, sin scope propio.
807
+ *
808
+ * ⚠️ **Vive tras el módulo `stock`, que es opt-in**: si la empresa no lo ha
809
+ * instalado, estas rutas responden `403` con `error: module_not_installed`,
810
+ * y eso NO es un problema de permisos. El libro de movimientos, el ajuste
811
+ * con motivo y la mercancía recibida son de todos y no pasan por aquí.
812
+ *
813
+ * Exactamente un almacén lleva `is_default`, y es el que hereda todo
814
+ * movimiento que no elige otro. El saldo por almacén es el REPARTO del
815
+ * contador global: su suma por artículo es exactamente `opening_stock`.
816
+ */
817
+ get warehouses(): {
818
+ list: (query?: RequestOptions["query"], options?: ReadOptions) => Promise<{
819
+ data: components["schemas"]["WarehouseResource"][];
820
+ }>;
821
+ get: (id: number | string, options?: ReadOptions) => Promise<{
822
+ data: components["schemas"]["WarehouseResource"];
823
+ }>;
824
+ create: (body: WarehouseRequest, options?: WriteOptions) => Promise<ResourceEnvelope<{
825
+ id: number;
826
+ name: string;
827
+ code: string | null;
828
+ address: string | null;
829
+ is_default: boolean;
830
+ is_active: boolean;
831
+ created_at: string | null;
832
+ updated_at: string | null;
833
+ }>>;
834
+ update: (id: number | string, body: WarehouseRequest, options?: WriteOptions) => Promise<ResourceEnvelope<{
835
+ id: number;
836
+ name: string;
837
+ code: string | null;
838
+ address: string | null;
839
+ is_default: boolean;
840
+ is_active: boolean;
841
+ created_at: string | null;
842
+ updated_at: string | null;
843
+ }>>;
844
+ /**
845
+ * Borra un almacén VACÍO y sin historia. Tres negativas con su código:
846
+ * `default_warehouse_required`, `stock_movements_attached` (su pasado
847
+ * explica saldos de hoy) y `stock_attached`. Para el que ya no se usa,
848
+ * `update` con `is_active: false`.
849
+ */
850
+ delete: (id: number | string, options?: ReadOptions) => Promise<{
851
+ success: string;
852
+ }>;
853
+ /**
854
+ * Las existencias de UN almacén, artículo a artículo — la pregunta que
855
+ * la dimensión vino a contestar. `only_with_stock` deja fuera los ceros.
856
+ */
857
+ stock: (id: number | string, query?: RequestOptions["query"], options?: ReadOptions) => Promise<{
858
+ data: components["schemas"]["ItemWarehouseStockResource"][];
859
+ meta: {
860
+ warehouse: components["schemas"]["WarehouseResource"];
861
+ };
862
+ }>;
863
+ };
794
864
  get<T = unknown>(path: string, query?: RequestOptions['query'], options?: ReadOptions): Promise<T>;
795
865
  post<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
796
866
  put<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
package/dist/client.js CHANGED
@@ -164,6 +164,39 @@ export class PimiaClient {
164
164
  uploadDocument: (id, document, options) => this.post(`/contracts/${id}/document`, toFormData({ document }), options),
165
165
  };
166
166
  }
167
+ /**
168
+ * Almacenes: la DIMENSIÓN del stock. Exige `items:read` / `items:write` —
169
+ * el almacén cuelga del catálogo que dimensiona, sin scope propio.
170
+ *
171
+ * ⚠️ **Vive tras el módulo `stock`, que es opt-in**: si la empresa no lo ha
172
+ * instalado, estas rutas responden `403` con `error: module_not_installed`,
173
+ * y eso NO es un problema de permisos. El libro de movimientos, el ajuste
174
+ * con motivo y la mercancía recibida son de todos y no pasan por aquí.
175
+ *
176
+ * Exactamente un almacén lleva `is_default`, y es el que hereda todo
177
+ * movimiento que no elige otro. El saldo por almacén es el REPARTO del
178
+ * contador global: su suma por artículo es exactamente `opening_stock`.
179
+ */
180
+ get warehouses() {
181
+ return {
182
+ list: (query, options) => this.get('/warehouses', query, options),
183
+ get: (id, options) => this.get(`/warehouses/${id}`, undefined, options),
184
+ create: (body, options) => this.post('/warehouses', body, options),
185
+ update: (id, body, options) => this.put(`/warehouses/${id}`, body, options),
186
+ /**
187
+ * Borra un almacén VACÍO y sin historia. Tres negativas con su código:
188
+ * `default_warehouse_required`, `stock_movements_attached` (su pasado
189
+ * explica saldos de hoy) y `stock_attached`. Para el que ya no se usa,
190
+ * `update` con `is_active: false`.
191
+ */
192
+ delete: (id, options) => this.delete(`/warehouses/${id}`, options),
193
+ /**
194
+ * Las existencias de UN almacén, artículo a artículo — la pregunta que
195
+ * la dimensión vino a contestar. `only_with_stock` deja fuera los ceros.
196
+ */
197
+ stock: (id, query, options) => this.get(`/warehouses/${id}/stock`, query, options),
198
+ };
199
+ }
167
200
  get(path, query, options) {
168
201
  return this.request(path, { ...options, method: 'GET', query });
169
202
  }
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * salen los tipos de `./api`.
7
7
  */
8
8
  export { PimiaClient, toFormData } from './client.js';
9
- export type { ContractRequest, ContractResource, CustomerRequest, CustomerResource, EstimateResource, EstimatesRequest, InvoiceResource, InvoicesRequest, PimiaClientOptions, RateLimit, ReadOptions, RequestOptions, ResourceEnvelope, ResponseMeta, ResponseWithMeta, WriteOptions, } from './client.js';
9
+ export type { ContractRequest, ContractResource, CustomerRequest, CustomerResource, EstimateResource, EstimatesRequest, InvoiceResource, InvoicesRequest, ItemWarehouseStockResource, PimiaClientOptions, RateLimit, ReadOptions, RequestOptions, ResourceEnvelope, ResponseMeta, ResponseWithMeta, WarehouseRequest, WarehouseResource, WriteOptions, } from './client.js';
10
10
  export { OAuth, createPkceChallenge, createState } from './oauth.js';
11
11
  export type { AuthorizationServerMetadata, AuthorizeUrlOptions, OAuthConfig, PkceChallenge, } from './oauth.js';
12
12
  export { MemoryTokenStore, isExpired, tokenSetFromResponse } from './tokens.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pimia/sdk",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Cliente TypeScript de la API de Pimia para apps de partner: OAuth con PKCE, rotación de refresh persistida, reintentos de rate limit y tipos generados del OpenAPI.",
5
5
  "license": "MIT",
6
6
  "author": "Pimia (https://pimia.es)",