generated from coulomb/repo-seed
Add document lifecycle tracking with order/production status
- Extended PDFStatus with full lifecycle: pending → uploading → in_basket → ordering → in_production → sent/canceled - Added shipDocument() and getDocumentStatus() API methods - Grouped UI sections: Ready to Upload, In Basket, In Production, Completed - Order button for documents in basket to place production order - Refresh button to check current status from Binect server - Display price and recipient address for uploaded documents - Status icons and color-coded indicators for each state Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -325,3 +325,151 @@ export async function testConnection(username: string, password: string): Promis
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Document status information returned by getDocumentStatus
|
||||
*/
|
||||
export interface DocumentStatusInfo {
|
||||
status: number;
|
||||
statusText: string;
|
||||
price?: number;
|
||||
recipientAddress?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ship a document (place order for production)
|
||||
*
|
||||
* This announces the document for delivery, transitioning it from
|
||||
* SHIPPABLE to PRODUCTION_QUEUE.
|
||||
*
|
||||
* @param documentId - Binect document ID
|
||||
* @param username - Binect username
|
||||
* @param password - Binect password
|
||||
* @returns Updated status info
|
||||
*/
|
||||
export async function shipDocument(
|
||||
documentId: number,
|
||||
username: string,
|
||||
password: string
|
||||
): Promise<DocumentStatusInfo> {
|
||||
console.log('[Binect API] Shipping document:', documentId);
|
||||
|
||||
try {
|
||||
const client = new BinectClient({
|
||||
username,
|
||||
password,
|
||||
});
|
||||
|
||||
// Send the document for production
|
||||
const sending = await client.sendings.send(String(documentId));
|
||||
|
||||
console.log('[Binect API] Document shipped successfully');
|
||||
console.log('[Binect API] New status:', sending.status);
|
||||
|
||||
return {
|
||||
status: sending.status,
|
||||
statusText: getStatusText(sending.status),
|
||||
price: sending.price,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[Binect API] Ship error:', error);
|
||||
|
||||
if (error instanceof BinectAuthError) {
|
||||
throw new BinectAPIError('Invalid credentials', 401);
|
||||
}
|
||||
|
||||
if (error instanceof BinectApiError) {
|
||||
// Check for insufficient balance (error code 2330)
|
||||
if (error.message.includes('2330') || error.message.includes('balance')) {
|
||||
throw new BinectAPIError('Insufficient account balance', 402);
|
||||
}
|
||||
throw BinectAPIError.fromBinectError(error);
|
||||
}
|
||||
|
||||
if (error instanceof BinectAPIError) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new BinectAPIError(
|
||||
`Failed to ship document: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current status of a document
|
||||
*
|
||||
* @param documentId - Binect document ID
|
||||
* @param username - Binect username
|
||||
* @param password - Binect password
|
||||
* @returns Current status info
|
||||
*/
|
||||
export async function getDocumentStatus(
|
||||
documentId: number,
|
||||
username: string,
|
||||
password: string
|
||||
): Promise<DocumentStatusInfo> {
|
||||
console.log('[Binect API] Getting document status:', documentId);
|
||||
|
||||
try {
|
||||
const client = new BinectClient({
|
||||
username,
|
||||
password,
|
||||
});
|
||||
|
||||
// Fetch document details
|
||||
const doc = await client.documents.get(String(documentId));
|
||||
|
||||
console.log('[Binect API] Document status:', doc.status);
|
||||
|
||||
// Extract price and recipient if available
|
||||
let price: number | undefined;
|
||||
let recipientAddress: string | undefined;
|
||||
|
||||
if (doc.letter?.letterData) {
|
||||
price = doc.letter.letterData.price?.priceAfterTax;
|
||||
recipientAddress = doc.letter.letterData.recipientAddress;
|
||||
}
|
||||
|
||||
return {
|
||||
status: doc.status.code,
|
||||
statusText: doc.status.text || getStatusText(doc.status.code),
|
||||
price,
|
||||
recipientAddress,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[Binect API] Get status error:', error);
|
||||
|
||||
if (error instanceof BinectAuthError) {
|
||||
throw new BinectAPIError('Invalid credentials', 401);
|
||||
}
|
||||
|
||||
if (error instanceof BinectApiError) {
|
||||
throw BinectAPIError.fromBinectError(error);
|
||||
}
|
||||
|
||||
if (error instanceof BinectAPIError) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new BinectAPIError(
|
||||
`Failed to get document status: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get human-readable status text for a Binect status code
|
||||
*/
|
||||
function getStatusText(statusCode: number): string {
|
||||
switch (statusCode) {
|
||||
case 1: return 'In preparation';
|
||||
case 2: return 'Ready to ship';
|
||||
case 3: return 'In production queue';
|
||||
case 4: return 'Printing';
|
||||
case 5: return 'Sent';
|
||||
case 6: return 'Canceled';
|
||||
case 7: return 'Has errors';
|
||||
default: return 'Unknown status';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user