generated from coulomb/repo-seed
Server sync, erroneous doc handling, and @binect/js v0.1.0 integration
- Add server sync to discover documents uploaded elsewhere (fixes missing basket documents issue) - Handle erroneous uploads: preserve binectDocumentId for delete button - Add "Delete from server" button for erroneous and canceled documents - Remove archive button for active documents (in_basket, in_production) - Auto-restore archived documents that have active status - Refactor to use @binect/js v0.1.0 features: - DocumentStatus enum instead of magic numbers - isErroneous(), getErrors() helper functions - getStatusDescription() for status text - Add binect-js improvement requirements document Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,10 @@ import {
|
||||
BinectClient,
|
||||
BinectApiError,
|
||||
BinectAuthError,
|
||||
DocumentStatus,
|
||||
isErroneous,
|
||||
getErrors,
|
||||
getStatusDescription,
|
||||
type Document as BinectDocument,
|
||||
type DocumentUploadOptions,
|
||||
EnvelopeType,
|
||||
@@ -225,25 +229,14 @@ export async function uploadPDF(
|
||||
console.log('[Binect API] Document ID:', doc.id);
|
||||
console.log('[Binect API] Document status:', doc.status);
|
||||
|
||||
// Check if document has errors
|
||||
if (doc.letter?.letterType === 'Error' && doc.letter.errors) {
|
||||
console.warn('[Binect API] Document has errors:', doc.letter.errors);
|
||||
const errorMessages = doc.letter.errors.map(e => e.message).join('; ');
|
||||
throw new BinectAPIError(
|
||||
`Document validation failed: ${errorMessages}`,
|
||||
200,
|
||||
doc
|
||||
);
|
||||
}
|
||||
|
||||
// Status code 7 = erroneous
|
||||
if (doc.status.code === 7) {
|
||||
console.error('[Binect API] Document is erroneous:', doc.status.text);
|
||||
throw new BinectAPIError(
|
||||
`Document is erroneous: ${doc.status.text}`,
|
||||
200,
|
||||
doc
|
||||
);
|
||||
// Log if document has errors (status ERRONEOUS)
|
||||
// But still return the document so we can track it and offer delete
|
||||
if (isErroneous(doc)) {
|
||||
console.warn('[Binect API] Document is erroneous:', doc.status.text);
|
||||
const errors = getErrors(doc);
|
||||
if (errors.length > 0) {
|
||||
console.warn('[Binect API] Document errors:', errors.map(e => e.message).join('; '));
|
||||
}
|
||||
}
|
||||
|
||||
return mapDocument(doc);
|
||||
@@ -369,7 +362,7 @@ export async function shipDocument(
|
||||
|
||||
return {
|
||||
status: sending.status,
|
||||
statusText: getStatusText(sending.status),
|
||||
statusText: getStatusDescription(sending.status),
|
||||
price: sending.price,
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -433,15 +426,18 @@ export async function getDocumentStatus(
|
||||
recipientAddress = doc.letter.letterData.recipientAddress;
|
||||
}
|
||||
|
||||
// Extract error details for erroneous documents (status 7)
|
||||
if (doc.status.code === 7 && doc.letter?.errors && doc.letter.errors.length > 0) {
|
||||
errorDetails = doc.letter.errors.map(e => e.message).join('; ');
|
||||
console.log('[Binect API] Document errors:', errorDetails);
|
||||
// Extract error details for erroneous documents
|
||||
if (isErroneous(doc)) {
|
||||
const errors = getErrors(doc);
|
||||
if (errors.length > 0) {
|
||||
errorDetails = errors.map(e => e.message).join('; ');
|
||||
console.log('[Binect API] Document errors:', errorDetails);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
status: doc.status.code,
|
||||
statusText: doc.status.text || getStatusText(doc.status.code),
|
||||
statusText: doc.status.text || getStatusDescription(doc.status.code),
|
||||
price,
|
||||
recipientAddress,
|
||||
errorDetails,
|
||||
@@ -472,17 +468,139 @@ export async function getDocumentStatus(
|
||||
}
|
||||
|
||||
/**
|
||||
* Get human-readable status text for a Binect status code
|
||||
* Server document info for sync
|
||||
*/
|
||||
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';
|
||||
export interface ServerDocument {
|
||||
id: number;
|
||||
filename: string;
|
||||
status: number;
|
||||
statusText: string;
|
||||
price?: number;
|
||||
recipientAddress?: string;
|
||||
errorDetails?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all shippable documents from the server
|
||||
*
|
||||
* @param username - Binect username
|
||||
* @param password - Binect password
|
||||
* @returns Array of server documents
|
||||
*/
|
||||
export async function listServerDocuments(
|
||||
username: string,
|
||||
password: string
|
||||
): Promise<ServerDocument[]> {
|
||||
console.log('[Binect API] Listing server documents...');
|
||||
|
||||
try {
|
||||
const client = new BinectClient({
|
||||
username,
|
||||
password,
|
||||
});
|
||||
|
||||
// Get shippable documents (status 2)
|
||||
console.log('[Binect API] Fetching shippable documents...');
|
||||
const shippableResponse = await client.documents.list();
|
||||
console.log('[Binect API] Shippable response:', JSON.stringify(shippableResponse));
|
||||
const shippable = shippableResponse.items || [];
|
||||
console.log('[Binect API] Found', shippable.length, 'shippable documents');
|
||||
|
||||
// Get erroneous documents (status 7)
|
||||
console.log('[Binect API] Fetching erroneous documents...');
|
||||
const errorsResponse = await client.documents.listErrors();
|
||||
console.log('[Binect API] Errors response:', JSON.stringify(errorsResponse));
|
||||
const erroneous = errorsResponse.items || [];
|
||||
console.log('[Binect API] Found', erroneous.length, 'erroneous documents');
|
||||
|
||||
// Combine and map to our format
|
||||
const allDocs = [...shippable, ...erroneous];
|
||||
|
||||
console.log('[Binect API] Total documents on server:', allDocs.length);
|
||||
|
||||
return allDocs.map(doc => {
|
||||
let errorDetails: string | undefined;
|
||||
if (isErroneous(doc)) {
|
||||
const errors = getErrors(doc);
|
||||
if (errors.length > 0) {
|
||||
errorDetails = errors.map(e => e.message).join('; ');
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: doc.id,
|
||||
filename: doc.filename || 'document.pdf',
|
||||
status: doc.status.code,
|
||||
statusText: doc.status.text || getStatusDescription(doc.status.code),
|
||||
price: doc.letter?.letterData?.price?.priceAfterTax,
|
||||
recipientAddress: doc.letter?.letterData?.recipientAddress,
|
||||
errorDetails,
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[Binect API] List documents error:', error);
|
||||
|
||||
if (error instanceof BinectAuthError) {
|
||||
throw new BinectAPIError('Invalid credentials', 401);
|
||||
}
|
||||
|
||||
if (error instanceof BinectApiError) {
|
||||
throw BinectAPIError.fromBinectError(error);
|
||||
}
|
||||
|
||||
throw new BinectAPIError(
|
||||
`Failed to list documents: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a document from the server
|
||||
*
|
||||
* @param documentId - Binect document ID
|
||||
* @param username - Binect username
|
||||
* @param password - Binect password
|
||||
*/
|
||||
export async function deleteDocument(
|
||||
documentId: number,
|
||||
username: string,
|
||||
password: string
|
||||
): Promise<void> {
|
||||
console.log('[Binect API] Deleting document:', documentId);
|
||||
|
||||
try {
|
||||
const client = new BinectClient({
|
||||
username,
|
||||
password,
|
||||
});
|
||||
|
||||
await client.documents.delete(String(documentId));
|
||||
console.log('[Binect API] Document deleted successfully');
|
||||
} catch (error) {
|
||||
console.error('[Binect API] Delete error:', error);
|
||||
|
||||
if (error instanceof BinectAuthError) {
|
||||
throw new BinectAPIError('Invalid credentials', 401);
|
||||
}
|
||||
|
||||
if (error instanceof BinectApiError) {
|
||||
if (error.status === 404) {
|
||||
// Already deleted, treat as success
|
||||
console.log('[Binect API] Document already deleted (404)');
|
||||
return;
|
||||
}
|
||||
throw BinectAPIError.fromBinectError(error);
|
||||
}
|
||||
|
||||
if (error instanceof BinectAPIError) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new BinectAPIError(
|
||||
`Failed to delete document: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-export DocumentStatus enum for use in other modules
|
||||
export { DocumentStatus };
|
||||
|
||||
Reference in New Issue
Block a user