@pimia/sdk 0.11.0 → 0.13.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/client.d.ts CHANGED
@@ -23,12 +23,29 @@ export type CustomerResource = Schemas['CustomerResource'];
23
23
  export type InvoiceResource = Schemas['InvoiceResource'];
24
24
  /** Presupuesto tal y como lo devuelve la API. */
25
25
  export type EstimateResource = Schemas['EstimateResource'];
26
+ /** Contrato de servicio tal y como lo devuelve la API. */
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'];
26
32
  /** Cuerpo de alta/edición de cliente. Incluye `customFields`. */
27
33
  export type CustomerRequest = Schemas['CustomerRequest'];
28
34
  /** Cuerpo de alta/edición de factura. Incluye `customFields`. */
29
35
  export type InvoicesRequest = Schemas['InvoicesRequest'];
30
36
  /** Cuerpo de alta/edición de presupuesto. Incluye `customFields`. */
31
37
  export type EstimatesRequest = Schemas['EstimatesRequest'];
38
+ /**
39
+ * Cuerpo de alta/edición de contrato. Sin `status` a propósito: el ciclo de
40
+ * vida va por sus acciones (`activate`/`cancel`/`renew`), nunca por el PUT.
41
+ */
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'];
32
49
  /**
33
50
  * El sobre `{ data: … }` de Laravel para las escrituras que el spec **no
34
51
  * tipa**.
@@ -561,6 +578,289 @@ export declare class PimiaClient {
561
578
  currency?: components["schemas"]["CurrencyResource"] | null;
562
579
  }>>;
563
580
  };
581
+ /**
582
+ * Contratos de servicio. Exige `contracts:read` / `contracts:write`.
583
+ *
584
+ * Un contrato GOBIERNA facturas recurrentes: su periodo se vuelve los
585
+ * límites de la recurrente. El ciclo de vida va por sus acciones — el
586
+ * `PUT` no acepta `status`, y fuera de borrador solo toca lo descriptivo
587
+ * (el periodo se cambia con `renew`, que sí propaga).
588
+ */
589
+ get contracts(): {
590
+ list: (query?: RequestOptions["query"], options?: ReadOptions) => Promise<{
591
+ data: components["schemas"]["ContractResource"][];
592
+ meta: {
593
+ contract_total_count: number;
594
+ };
595
+ }>;
596
+ get: (id: number | string, options?: ReadOptions) => Promise<{
597
+ data: components["schemas"]["ContractResource"];
598
+ }>;
599
+ create: (body: ContractRequest, options?: WriteOptions) => Promise<ResourceEnvelope<{
600
+ id: number;
601
+ title: string;
602
+ description: string | null;
603
+ contract_number: string | null;
604
+ customer_id: number | null;
605
+ company_id: number | null;
606
+ creator_id: number | null;
607
+ currency_id: number | null;
608
+ status: string;
609
+ ha_vencido: boolean;
610
+ starts_at: string | null;
611
+ ends_at: string | null;
612
+ amount: number | null;
613
+ billing_every: string;
614
+ billing_anchor_day: number | null;
615
+ renewal_mode: string;
616
+ notice_days: number | null;
617
+ notice_days_effective: number;
618
+ has_document: boolean;
619
+ estimate_id: number | null;
620
+ cancelled_at: string | null;
621
+ fields?: components["schemas"]["CustomFieldValueResource"][];
622
+ customer?: components["schemas"]["CustomerResource"] | null;
623
+ estimate?: components["schemas"]["EstimateResource"] | null;
624
+ recurring_invoices?: components["schemas"]["RecurringInvoiceResource"][];
625
+ invoices?: components["schemas"]["InvoiceResource"][];
626
+ }>>;
627
+ update: (id: number | string, body: ContractRequest, options?: WriteOptions) => Promise<ResourceEnvelope<{
628
+ id: number;
629
+ title: string;
630
+ description: string | null;
631
+ contract_number: string | null;
632
+ customer_id: number | null;
633
+ company_id: number | null;
634
+ creator_id: number | null;
635
+ currency_id: number | null;
636
+ status: string;
637
+ ha_vencido: boolean;
638
+ starts_at: string | null;
639
+ ends_at: string | null;
640
+ amount: number | null;
641
+ billing_every: string;
642
+ billing_anchor_day: number | null;
643
+ renewal_mode: string;
644
+ notice_days: number | null;
645
+ notice_days_effective: number;
646
+ has_document: boolean;
647
+ estimate_id: number | null;
648
+ cancelled_at: string | null;
649
+ fields?: components["schemas"]["CustomFieldValueResource"][];
650
+ customer?: components["schemas"]["CustomerResource"] | null;
651
+ estimate?: components["schemas"]["EstimateResource"] | null;
652
+ recurring_invoices?: components["schemas"]["RecurringInvoiceResource"][];
653
+ invoices?: components["schemas"]["InvoiceResource"][];
654
+ }>>;
655
+ /**
656
+ * Activa el contrato: DRAFT → ACTIVE, lo numera, y crea la recurrente
657
+ * gobernada — o adopta la de `recurringInvoiceId` (misma empresa y
658
+ * mismo cliente; sus líneas e impuestos no se tocan).
659
+ *
660
+ * Exige `contracts:write` **e** `invoices:write`: la recurrente que
661
+ * nace emitirá facturas por su cuenta. Manda `idempotencyKey` —una
662
+ * clave estable del estilo `contract:{id}:activate`— y el reintento
663
+ * tras un timeout no te creará una segunda recurrente.
664
+ */
665
+ activate: (id: number | string, options?: WriteOptions & {
666
+ recurringInvoiceId?: number | string;
667
+ }) => Promise<ResourceEnvelope<{
668
+ id: number;
669
+ title: string;
670
+ description: string | null;
671
+ contract_number: string | null;
672
+ customer_id: number | null;
673
+ company_id: number | null;
674
+ creator_id: number | null;
675
+ currency_id: number | null;
676
+ status: string;
677
+ ha_vencido: boolean;
678
+ starts_at: string | null;
679
+ ends_at: string | null;
680
+ amount: number | null;
681
+ billing_every: string;
682
+ billing_anchor_day: number | null;
683
+ renewal_mode: string;
684
+ notice_days: number | null;
685
+ notice_days_effective: number;
686
+ has_document: boolean;
687
+ estimate_id: number | null;
688
+ cancelled_at: string | null;
689
+ fields?: components["schemas"]["CustomFieldValueResource"][];
690
+ customer?: components["schemas"]["CustomerResource"] | null;
691
+ estimate?: components["schemas"]["EstimateResource"] | null;
692
+ recurring_invoices?: components["schemas"]["RecurringInvoiceResource"][];
693
+ invoices?: components["schemas"]["InvoiceResource"][];
694
+ }>>;
695
+ /**
696
+ * Cancela: sus recurrentes quedan en pausa (`ON_HOLD`) y las facturas
697
+ * emitidas conservan el rastro entero.
698
+ */
699
+ cancel: (id: number | string, options?: WriteOptions) => Promise<ResourceEnvelope<{
700
+ id: number;
701
+ title: string;
702
+ description: string | null;
703
+ contract_number: string | null;
704
+ customer_id: number | null;
705
+ company_id: number | null;
706
+ creator_id: number | null;
707
+ currency_id: number | null;
708
+ status: string;
709
+ ha_vencido: boolean;
710
+ starts_at: string | null;
711
+ ends_at: string | null;
712
+ amount: number | null;
713
+ billing_every: string;
714
+ billing_anchor_day: number | null;
715
+ renewal_mode: string;
716
+ notice_days: number | null;
717
+ notice_days_effective: number;
718
+ has_document: boolean;
719
+ estimate_id: number | null;
720
+ cancelled_at: string | null;
721
+ fields?: components["schemas"]["CustomFieldValueResource"][];
722
+ customer?: components["schemas"]["CustomerResource"] | null;
723
+ estimate?: components["schemas"]["EstimateResource"] | null;
724
+ recurring_invoices?: components["schemas"]["RecurringInvoiceResource"][];
725
+ invoices?: components["schemas"]["InvoiceResource"][];
726
+ }>>;
727
+ /**
728
+ * Renovación manual: extiende `ends_at` (posterior al fin actual) y lo
729
+ * propaga a las recurrentes gobernadas, reviviendo las completadas por
730
+ * el límite viejo.
731
+ */
732
+ renew: (id: number | string, endsAt: string, options?: WriteOptions) => Promise<ResourceEnvelope<{
733
+ id: number;
734
+ title: string;
735
+ description: string | null;
736
+ contract_number: string | null;
737
+ customer_id: number | null;
738
+ company_id: number | null;
739
+ creator_id: number | null;
740
+ currency_id: number | null;
741
+ status: string;
742
+ ha_vencido: boolean;
743
+ starts_at: string | null;
744
+ ends_at: string | null;
745
+ amount: number | null;
746
+ billing_every: string;
747
+ billing_anchor_day: number | null;
748
+ renewal_mode: string;
749
+ notice_days: number | null;
750
+ notice_days_effective: number;
751
+ has_document: boolean;
752
+ estimate_id: number | null;
753
+ cancelled_at: string | null;
754
+ fields?: components["schemas"]["CustomFieldValueResource"][];
755
+ customer?: components["schemas"]["CustomerResource"] | null;
756
+ estimate?: components["schemas"]["EstimateResource"] | null;
757
+ recurring_invoices?: components["schemas"]["RecurringInvoiceResource"][];
758
+ invoices?: components["schemas"]["InvoiceResource"][];
759
+ }>>;
760
+ /**
761
+ * El enlace del PDF para el cliente final: URL FIRMADA con caducidad.
762
+ * Un contrato en borrador —sin número— es un 422.
763
+ */
764
+ sharedLink: (id: number | string, options?: ReadOptions) => Promise<{
765
+ data: {
766
+ url: string;
767
+ expires_at: string;
768
+ };
769
+ }>;
770
+ /**
771
+ * Sube (o reemplaza: un fichero por colección) el contrato FIRMADO —
772
+ * el papel escaneado. Multiparte por `POST` dedicado; el `FormData` lo
773
+ * arma el atajo, no le pongas `content-type`.
774
+ */
775
+ uploadDocument: (id: number | string, document: Blob, options?: WriteOptions) => Promise<ResourceEnvelope<{
776
+ id: number;
777
+ title: string;
778
+ description: string | null;
779
+ contract_number: string | null;
780
+ customer_id: number | null;
781
+ company_id: number | null;
782
+ creator_id: number | null;
783
+ currency_id: number | null;
784
+ status: string;
785
+ ha_vencido: boolean;
786
+ starts_at: string | null;
787
+ ends_at: string | null;
788
+ amount: number | null;
789
+ billing_every: string;
790
+ billing_anchor_day: number | null;
791
+ renewal_mode: string;
792
+ notice_days: number | null;
793
+ notice_days_effective: number;
794
+ has_document: boolean;
795
+ estimate_id: number | null;
796
+ cancelled_at: string | null;
797
+ fields?: components["schemas"]["CustomFieldValueResource"][];
798
+ customer?: components["schemas"]["CustomerResource"] | null;
799
+ estimate?: components["schemas"]["EstimateResource"] | null;
800
+ recurring_invoices?: components["schemas"]["RecurringInvoiceResource"][];
801
+ invoices?: components["schemas"]["InvoiceResource"][];
802
+ }>>;
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
+ };
564
864
  get<T = unknown>(path: string, query?: RequestOptions['query'], options?: ReadOptions): Promise<T>;
565
865
  post<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
566
866
  put<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
package/dist/client.js CHANGED
@@ -112,6 +112,91 @@ export class PimiaClient {
112
112
  },
113
113
  };
114
114
  }
115
+ /**
116
+ * Contratos de servicio. Exige `contracts:read` / `contracts:write`.
117
+ *
118
+ * Un contrato GOBIERNA facturas recurrentes: su periodo se vuelve los
119
+ * límites de la recurrente. El ciclo de vida va por sus acciones — el
120
+ * `PUT` no acepta `status`, y fuera de borrador solo toca lo descriptivo
121
+ * (el periodo se cambia con `renew`, que sí propaga).
122
+ */
123
+ get contracts() {
124
+ return {
125
+ list: (query, options) => this.get('/contracts', query, options),
126
+ get: (id, options) => this.get(`/contracts/${id}`, undefined, options),
127
+ create: (body, options) => this.post('/contracts', body, options),
128
+ update: (id, body, options) => this.put(`/contracts/${id}`, body, options),
129
+ /**
130
+ * Activa el contrato: DRAFT → ACTIVE, lo numera, y crea la recurrente
131
+ * gobernada — o adopta la de `recurringInvoiceId` (misma empresa y
132
+ * mismo cliente; sus líneas e impuestos no se tocan).
133
+ *
134
+ * Exige `contracts:write` **e** `invoices:write`: la recurrente que
135
+ * nace emitirá facturas por su cuenta. Manda `idempotencyKey` —una
136
+ * clave estable del estilo `contract:{id}:activate`— y el reintento
137
+ * tras un timeout no te creará una segunda recurrente.
138
+ */
139
+ activate: (id, options) => {
140
+ const { recurringInvoiceId, ...resto } = options ?? {};
141
+ return this.post(`/contracts/${id}/activate`, recurringInvoiceId === undefined ? {} : { recurring_invoice_id: recurringInvoiceId }, resto);
142
+ },
143
+ /**
144
+ * Cancela: sus recurrentes quedan en pausa (`ON_HOLD`) y las facturas
145
+ * emitidas conservan el rastro entero.
146
+ */
147
+ cancel: (id, options) => this.post(`/contracts/${id}/cancel`, {}, options),
148
+ /**
149
+ * Renovación manual: extiende `ends_at` (posterior al fin actual) y lo
150
+ * propaga a las recurrentes gobernadas, reviviendo las completadas por
151
+ * el límite viejo.
152
+ */
153
+ renew: (id, endsAt, options) => this.post(`/contracts/${id}/renew`, { ends_at: endsAt }, options),
154
+ /**
155
+ * El enlace del PDF para el cliente final: URL FIRMADA con caducidad.
156
+ * Un contrato en borrador —sin número— es un 422.
157
+ */
158
+ sharedLink: (id, options) => this.get(`/contracts/${id}/shared-link`, undefined, options),
159
+ /**
160
+ * Sube (o reemplaza: un fichero por colección) el contrato FIRMADO —
161
+ * el papel escaneado. Multiparte por `POST` dedicado; el `FormData` lo
162
+ * arma el atajo, no le pongas `content-type`.
163
+ */
164
+ uploadDocument: (id, document, options) => this.post(`/contracts/${id}/document`, toFormData({ document }), options),
165
+ };
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
+ }
115
200
  get(path, query, options) {
116
201
  return this.request(path, { ...options, method: 'GET', query });
117
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 { 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';
@@ -20,6 +20,14 @@ export declare const SCOPES: {
20
20
  readonly invoicesWrite: "invoices:write";
21
21
  readonly estimatesRead: "estimates:read";
22
22
  readonly estimatesWrite: "estimates:write";
23
+ /** Leer contratos de servicio: periodo, estado, sus recurrentes. */
24
+ readonly contractsRead: "contracts:read";
25
+ /**
26
+ * Gestionar contratos: crear, activar, renovar y cancelar — pueden
27
+ * comprometer periodos de facturación futuros. Activar exige además
28
+ * `invoices:write` (la recurrente que nace emitirá facturas por su cuenta).
29
+ */
30
+ readonly contractsWrite: "contracts:write";
23
31
  readonly customersRead: "customers:read";
24
32
  readonly customersWrite: "customers:write";
25
33
  readonly expensesRead: "expenses:read";
package/dist/index.js CHANGED
@@ -16,6 +16,14 @@ export const SCOPES = {
16
16
  invoicesWrite: 'invoices:write',
17
17
  estimatesRead: 'estimates:read',
18
18
  estimatesWrite: 'estimates:write',
19
+ /** Leer contratos de servicio: periodo, estado, sus recurrentes. */
20
+ contractsRead: 'contracts:read',
21
+ /**
22
+ * Gestionar contratos: crear, activar, renovar y cancelar — pueden
23
+ * comprometer periodos de facturación futuros. Activar exige además
24
+ * `invoices:write` (la recurrente que nace emitirá facturas por su cuenta).
25
+ */
26
+ contractsWrite: 'contracts:write',
19
27
  customersRead: 'customers:read',
20
28
  customersWrite: 'customers:write',
21
29
  expensesRead: 'expenses:read',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pimia/sdk",
3
- "version": "0.11.0",
3
+ "version": "0.13.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)",