@autobusal/admin-api-consumers 1.1.0 → 1.2.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.1
4
+
5
+ ### Fixed
6
+
7
+ - **The token panel updates without a reload** - toggle/revoke/regenerate invalidate the consumer they changed. The button also reads "Generate Token" while no token exists. (Audit ADM-04f.)
8
+
9
+ ## 1.2.0
10
+
11
+ ### Added
12
+
13
+ - **Credit limit on the partner form, running balance on receivables.** A
14
+ Mode 1 partner now sells against a running account (obtapi Payments\
15
+ External\Charge): every sale debits the net they owe, cancellations
16
+ credit it back, and recorded settlements raise it. `credit_limit` is the
17
+ floor - 0 means prepaid (deposit before selling), a positive number means
18
+ postpaid down to -that-much. The receivables table shows the live
19
+ `balance` and `headroom` alongside the statement figures, deliberately
20
+ from two books: when they disagree, something needs investigating.
21
+
3
22
  All notable changes to `@autobusal/admin-api-consumers` are documented here.
4
23
  This project adheres to [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
5
24
  and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
package/Manage.tsx CHANGED
@@ -131,6 +131,16 @@ const Manage = ({ url, t }: Props): JSX.Element => {
131
131
  type: 'select',
132
132
  value: data?.user.comissions?.unique ?? 0,
133
133
  values: getAllowed(t)
134
+ }, {
135
+ // Claude - 2026-08-22: the floor of the partner's running
136
+ // account. 0 = prepaid (they deposit before they can sell);
137
+ // a positive number = postpaid down to -that-much. "Unlimited"
138
+ // is a big number typed on purpose, never a switch.
139
+ label: t('admin_api_consumers.manage.credit_limit', { ns: 'common' }),
140
+ name: 'credit_limit',
141
+ type: 'text',
142
+ value: data?.credit_limit ?? 0,
143
+ rules: 'required|numeric'
134
144
  }, {
135
145
  label: t('admin_api_consumers.manage.status', { ns: 'common' }),
136
146
  name: 'status',
package/Receivables.tsx CHANGED
@@ -50,6 +50,8 @@ const Receivables = ({ url, t }: Props): JSX.Element => {
50
50
  <th>{ t('admin_api_consumers.receivables.net', { ns: 'common' }) }</th>
51
51
  <th>{ t('admin_api_consumers.receivables.settled', { ns: 'common' }) }</th>
52
52
  <th>{ t('admin_api_consumers.receivables.outstanding', { ns: 'common' }) }</th>
53
+ <th>{ t('admin_api_consumers.receivables.balance', { ns: 'common' }) }</th>
54
+ <th>{ t('admin_api_consumers.receivables.headroom', { ns: 'common' }) }</th>
53
55
  <th />
54
56
  </tr>
55
57
  </thead>
@@ -65,6 +67,11 @@ const Receivables = ({ url, t }: Props): JSX.Element => {
65
67
  <td>{ row.net.toFixed(2) }</td>
66
68
  <td>{ row.settled.toFixed(2) }</td>
67
69
  <td>{ row.outstanding.toFixed(2) }</td>
70
+ { /* the running account: negative is what they owe right
71
+ now; headroom is what they can still sell before
72
+ their credit floor refuses them */ }
73
+ <td>{ row.balance.toFixed(2) }</td>
74
+ <td>{ row.headroom.toFixed(2) }</td>
68
75
  <td>
69
76
  <Link to={ `${ url }/receivables/${ row.agent_id }?from=${ from }&to=${ to }` }>
70
77
  { t('admin_api_consumers.receivables.view', { ns: 'common' }) }
package/TokenManager.tsx CHANGED
@@ -78,7 +78,7 @@ const TokenManager = ({ id, hasToken, enabled, t }: Props): JSX.Element => {
78
78
  subtype="secondary"
79
79
  noMargin
80
80
  loading={ isPendingRegenerate }
81
- text={ <><FiRefreshCw /> { t('admin_api_consumers.token.regenerate', { ns: 'common' }) }</> }
81
+ text={ <><FiRefreshCw /> { t(hasToken ? 'admin_api_consumers.token.regenerate' : 'admin_api_consumers.token.generate', { ns: 'common' }) }</> }
82
82
  onClick={ onRegenerate }
83
83
  />
84
84
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/admin-api-consumers",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "author": "Ferjolt Ozuni",
5
5
  "type": "module",
6
6
  "main": "index.ts"
package/services.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { UseMutationResult, UseQueryResult, UseSuspenseQueryResult, useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query';
1
+ import { UseMutationResult, UseQueryResult, UseSuspenseQueryResult, useMutation, useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query';
2
2
  import { apiClient } from '@autobusal/providers';
3
3
  import { PaginationData } from '@autobusal/providers/types/pagination';
4
4
  import { TableParamsData } from '@autobusal/providers/types/other';
@@ -106,8 +106,17 @@ export const useDeleteApiConsumer = (): UseMutationResult<void, Error, number, u
106
106
  })
107
107
  );
108
108
 
109
- export const useToggleApiConsumer = (): UseMutationResult<void, Error, { id: number, api: number }, unknown> => (
110
- useMutation({
109
+ /*
110
+ * Claude - 2026-08-22 (audit finding ADM-04f): the token panel only showed
111
+ * a toggle/revoke/regenerate's effect after a full page reload - an admin
112
+ * could reasonably believe Revoke had failed. Each mutation now
113
+ * invalidates the consumer it changed, so the panel redraws from the
114
+ * server's answer immediately.
115
+ */
116
+ export const useToggleApiConsumer = (): UseMutationResult<void, Error, { id: number, api: number }, unknown> => {
117
+ const client = useQueryClient();
118
+
119
+ return useMutation({
111
120
  mutationKey: ['admin-api-consumers-toggle'],
112
121
  mutationFn: async ({ id, api }: { id: number, api: number }) => (
113
122
  await apiClient
@@ -115,12 +124,17 @@ export const useToggleApiConsumer = (): UseMutationResult<void, Error, { id: num
115
124
  .then(response => (
116
125
  response.data
117
126
  ))
118
- )
119
- })
120
- );
127
+ ),
128
+ onSuccess: (_, { id }): void => {
129
+ client.invalidateQueries({ queryKey: ['admin-api-consumers-manage', { id }] });
130
+ }
131
+ });
132
+ };
121
133
 
122
- export const useRevokeApiConsumerToken = (): UseMutationResult<void, Error, number, unknown> => (
123
- useMutation({
134
+ export const useRevokeApiConsumerToken = (): UseMutationResult<void, Error, number, unknown> => {
135
+ const client = useQueryClient();
136
+
137
+ return useMutation({
124
138
  mutationKey: ['admin-api-consumers-revoke'],
125
139
  mutationFn: async (id: number) => (
126
140
  await apiClient
@@ -128,12 +142,17 @@ export const useRevokeApiConsumerToken = (): UseMutationResult<void, Error, numb
128
142
  .then(response => (
129
143
  response.data
130
144
  ))
131
- )
132
- })
133
- );
145
+ ),
146
+ onSuccess: (_, id): void => {
147
+ client.invalidateQueries({ queryKey: ['admin-api-consumers-manage', { id }] });
148
+ }
149
+ });
150
+ };
134
151
 
135
- export const useRegenerateApiConsumerToken = (): UseMutationResult<{ api_token: string }, Error, number, unknown> => (
136
- useMutation({
152
+ export const useRegenerateApiConsumerToken = (): UseMutationResult<{ api_token: string }, Error, number, unknown> => {
153
+ const client = useQueryClient();
154
+
155
+ return useMutation({
137
156
  mutationKey: ['admin-api-consumers-regenerate'],
138
157
  mutationFn: async (id: number) => (
139
158
  await apiClient
@@ -141,9 +160,12 @@ export const useRegenerateApiConsumerToken = (): UseMutationResult<{ api_token:
141
160
  .then(response => (
142
161
  response.data
143
162
  ))
144
- )
145
- })
146
- );
163
+ ),
164
+ onSuccess: (_, id): void => {
165
+ client.invalidateQueries({ queryKey: ['admin-api-consumers-manage', { id }] });
166
+ }
167
+ });
168
+ };
147
169
 
148
170
  // Edited: Ferjolt Ozuni - Date: 2026-07-27
149
171
  // Package 3 - API partner receivables reports + settlements
package/types.ts CHANGED
@@ -6,6 +6,10 @@ export interface ApiConsumerData {
6
6
  operators: (number | string)[]
7
7
  external_providers: (number | string)[]
8
8
  is_api_consumer: boolean
9
+ // Claude - 2026-08-22: the running account and its floor - see
10
+ // ReceivableData below for what they mean
11
+ funds?: number
12
+ credit_limit?: number
9
13
  user: {
10
14
  id: number
11
15
  email: string
@@ -31,6 +35,13 @@ export interface ReceivableData {
31
35
  net: number
32
36
  settled: number
33
37
  outstanding: number
38
+ // Claude - 2026-08-22: the LIVE running account (debited per sale,
39
+ // credited by settlements) and its floor - alongside the statement
40
+ // figures, which describe the same debt from the frozen columns. When
41
+ // balance and -outstanding disagree, something needs investigating.
42
+ balance: number
43
+ credit_limit: number
44
+ headroom: number
34
45
  }
35
46
 
36
47
  export interface ReceivableOrderData {