Add permissions and types for invoice recipients

This commit is contained in:
Constantin Graf
2026-07-23 21:51:12 +02:00
parent 114a32536d
commit b22132b0f2
4 changed files with 186 additions and 34 deletions

View File

@@ -80,6 +80,10 @@ class PermissionStore
'invoices:update',
'invoices:download',
'invoices:delete',
'invoice-recipients:view',
'invoice-recipients:create',
'invoice-recipients:update',
'invoice-recipients:delete',
'invoice-settings:view',
'invoice-settings:update',
],
@@ -147,6 +151,10 @@ class PermissionStore
'invoices:update',
'invoices:download',
'invoices:delete',
'invoice-recipients:view',
'invoice-recipients:create',
'invoice-recipients:update',
'invoice-recipients:delete',
'invoice-settings:view',
'invoice-settings:update',
],
@@ -203,6 +211,10 @@ class PermissionStore
'invoices:update',
'invoices:download',
'invoices:delete',
'invoice-recipients:view',
'invoice-recipients:create',
'invoice-recipients:update',
'invoice-recipients:delete',
'invoice-settings:view',
'invoice-settings:update',
],

View File

@@ -1,7 +1,7 @@
{
"Billing": {
"repository": "solidtime-io/extension-billing",
"ref": "v0.0.3"
"ref": "v0.0.4"
},
"Services": {
"repository": "solidtime-io/extension-services",
@@ -9,6 +9,6 @@
},
"Invoicing": {
"repository": "solidtime-io/extension-invoicing",
"ref": "v0.0.1"
"ref": "feature/recipients"
}
}

View File

@@ -117,6 +117,8 @@ export type DetailedInvoiceResponse = ZodiosResponseByAlias<SolidTimeApi, 'getIn
export type DetailedInvoice = DetailedInvoiceResponse['data'];
export type InvoiceIndexEntry = ZodiosResponseByAlias<SolidTimeApi, 'getInvoices'>['data'][0];
export type InvoiceRecipient = ZodiosResponseByAlias<SolidTimeApi, 'getInvoiceRecipients'>['data'][0];
export type InvoiceRecipientBody = ZodiosBodyByAlias<SolidTimeApi, 'createInvoiceRecipient'>;
export type UpdateInvoiceSettings = ZodiosBodyByAlias<SolidTimeApi, 'updateInvoiceSettings'>;

View File

@@ -45,14 +45,54 @@ const InvitationResource = z
const InvitationStoreRequest = z
.object({ email: z.string().email(), role: z.enum(['admin', 'manager', 'employee']) })
.passthrough();
const InvoiceRecipientResource = z
.object({
id: z.string(),
organization_id: z.string(),
name: z.string(),
vatin: z.union([z.string(), z.null()]),
address_line_1: z.union([z.string(), z.null()]),
address_line_2: z.union([z.string(), z.null()]),
address_line_3: z.union([z.string(), z.null()]),
address_post_code: z.union([z.string(), z.null()]),
address_city: z.union([z.string(), z.null()]),
address_country: z.union([z.string(), z.null()]),
phone: z.union([z.string(), z.null()]),
email: z.union([z.string(), z.null()]),
is_archived: z.boolean(),
archived_at: z.union([z.string(), z.null()]),
invoices_count: z.number().int(),
has_non_draft_invoices: z.boolean(),
created_at: z.union([z.string(), z.null()]),
updated_at: z.union([z.string(), z.null()]),
})
.passthrough();
const InvoiceRecipientCollection = z.array(InvoiceRecipientResource);
const InvoiceRecipientRequest = z
.object({
name: z.string(),
vatin: z.union([z.string(), z.null()]).optional(),
address_line_1: z.union([z.string(), z.null()]).optional(),
address_line_2: z.union([z.string(), z.null()]).optional(),
address_line_3: z.union([z.string(), z.null()]).optional(),
address_post_code: z.union([z.string(), z.null()]).optional(),
address_city: z.union([z.string(), z.null()]).optional(),
address_country: z.union([z.string(), z.null()]).optional(),
phone: z.union([z.string(), z.null()]).optional(),
email: z.union([z.string(), z.null()]).optional(),
is_archived: z.boolean().optional(),
})
.passthrough();
const InvoiceResource = z
.object({
id: z.string(),
organization_id: z.string(),
invoice_recipient_id: z.string(),
reference: z.string(),
seller_name: z.string(),
buyer_name: z.string(),
recipient: z.string(),
status: z.string(),
status_label: z.string(),
date: z.string(),
due_at: z.string(),
paid_date: z.string(),
@@ -76,16 +116,7 @@ const InvoiceStoreRequest = z
seller_address_country: z.union([z.string(), z.null()]).optional(),
seller_phone: z.union([z.string(), z.null()]).optional(),
seller_email: z.union([z.string(), z.null()]).optional(),
buyer_name: z.string(),
buyer_vatin: z.union([z.string(), z.null()]).optional(),
buyer_address_line_1: z.union([z.string(), z.null()]).optional(),
buyer_address_line_2: z.union([z.string(), z.null()]).optional(),
buyer_address_line_3: z.union([z.string(), z.null()]).optional(),
buyer_address_post_code: z.union([z.string(), z.null()]).optional(),
buyer_address_city: z.union([z.string(), z.null()]).optional(),
buyer_address_country: z.union([z.string(), z.null()]).optional(),
buyer_phone: z.union([z.string(), z.null()]).optional(),
buyer_email: z.union([z.string(), z.null()]).optional(),
invoice_recipient_id: z.string(),
date: z.string(),
billing_period_start: z.union([z.string(), z.null()]).optional(),
billing_period_end: z.union([z.string(), z.null()]).optional(),
@@ -130,6 +161,7 @@ const DetailedInvoiceResource = z
.object({
id: z.string(),
organization_id: z.string(),
invoice_recipient_id: z.string(),
reference: z.string(),
seller_name: z.string(),
seller_vatin: z.string(),
@@ -141,16 +173,7 @@ const DetailedInvoiceResource = z
seller_address_country: z.string(),
seller_phone: z.string(),
seller_email: z.string(),
buyer_name: z.string(),
buyer_vatin: z.string(),
buyer_address_line_1: z.string(),
buyer_address_line_2: z.string(),
buyer_address_line_3: z.string(),
buyer_address_post_code: z.string(),
buyer_address_city: z.string(),
buyer_address_country: z.string(),
buyer_phone: z.string(),
buyer_email: z.string(),
recipient: InvoiceRecipientResource,
paid_date: z.string(),
due_at: z.string(),
discount_type: z.string(),
@@ -171,7 +194,7 @@ const DetailedInvoiceResource = z
entries: z.array(InvoiceEntryResource),
})
.passthrough();
const InvoiceStatus = z.enum(['draft', 'sent', 'cancelled']);
const InvoiceStatus = z.enum(['draft', 'sent', 'paid', 'cancelled']);
const InvoiceUpdateRequest = z
.object({
status: InvoiceStatus,
@@ -187,16 +210,7 @@ const InvoiceUpdateRequest = z
seller_address_country: z.union([z.string(), z.null()]),
seller_phone: z.union([z.string(), z.null()]),
seller_email: z.union([z.string(), z.null()]),
buyer_name: z.string(),
buyer_vatin: z.union([z.string(), z.null()]),
buyer_address_line_1: z.union([z.string(), z.null()]),
buyer_address_line_2: z.union([z.string(), z.null()]),
buyer_address_line_3: z.union([z.string(), z.null()]),
buyer_address_post_code: z.union([z.string(), z.null()]),
buyer_address_city: z.union([z.string(), z.null()]),
buyer_address_country: z.union([z.string(), z.null()]),
buyer_phone: z.union([z.string(), z.null()]),
buyer_email: z.union([z.string(), z.null()]),
invoice_recipient_id: z.string(),
date: z.string(),
billing_period_start: z.union([z.string(), z.null()]),
billing_period_end: z.union([z.string(), z.null()]),
@@ -1885,6 +1899,125 @@ const endpoints = makeApi([
},
],
},
{
method: 'get',
path: '/v1/organizations/:organization/invoice-recipients',
alias: 'getInvoiceRecipients',
requestFormat: 'json',
parameters: [
{
name: 'organization',
type: 'Path',
schema: z.string(),
},
],
response: z.object({ data: InvoiceRecipientCollection }).passthrough(),
},
{
method: 'post',
path: '/v1/organizations/:organization/invoice-recipients',
alias: 'createInvoiceRecipient',
requestFormat: 'json',
parameters: [
{
name: 'body',
type: 'Body',
schema: InvoiceRecipientRequest,
},
{
name: 'organization',
type: 'Path',
schema: z.string(),
},
],
response: z.object({ data: InvoiceRecipientResource }).passthrough(),
},
{
method: 'get',
path: '/v1/organizations/:organization/invoice-recipients/:invoiceRecipient',
alias: 'getInvoiceRecipient',
requestFormat: 'json',
parameters: [
{
name: 'organization',
type: 'Path',
schema: z.string(),
},
{
name: 'invoiceRecipient',
type: 'Path',
schema: z.string(),
},
],
response: z.object({ data: InvoiceRecipientResource }).passthrough(),
},
{
method: 'put',
path: '/v1/organizations/:organization/invoice-recipients/:invoiceRecipient',
alias: 'updateInvoiceRecipient',
requestFormat: 'json',
parameters: [
{
name: 'body',
type: 'Body',
schema: InvoiceRecipientRequest,
},
{
name: 'organization',
type: 'Path',
schema: z.string(),
},
{
name: 'invoiceRecipient',
type: 'Path',
schema: z.string(),
},
],
response: z.object({ data: InvoiceRecipientResource }).passthrough(),
},
{
method: 'post',
path: '/v1/organizations/:organization/invoice-recipients/:invoiceRecipient/duplicate',
alias: 'duplicateInvoiceRecipient',
requestFormat: 'json',
parameters: [
{
name: 'body',
type: 'Body',
schema: InvoiceRecipientRequest,
},
{
name: 'organization',
type: 'Path',
schema: z.string(),
},
{
name: 'invoiceRecipient',
type: 'Path',
schema: z.string(),
},
],
response: z.object({ data: InvoiceRecipientResource }).passthrough(),
},
{
method: 'delete',
path: '/v1/organizations/:organization/invoice-recipients/:invoiceRecipient',
alias: 'deleteInvoiceRecipient',
requestFormat: 'json',
parameters: [
{
name: 'organization',
type: 'Path',
schema: z.string(),
},
{
name: 'invoiceRecipient',
type: 'Path',
schema: z.string(),
},
],
response: z.void(),
},
{
method: 'get',
path: '/v1/organizations/:organization/invoices',
@@ -1901,6 +2034,11 @@ const endpoints = makeApi([
type: 'Query',
schema: z.number().int().gte(1).lte(2147483647).optional(),
},
{
name: 'status',
type: 'Query',
schema: InvoiceStatus.optional(),
},
],
response: z.object({ data: InvoiceCollection }).passthrough(),
errors: [