- Add TASK-2026-01-25-OQI-005-PAYMENTS-ADVANCED folder - Update FRONTEND_INVENTORY: payments 4→8, progress 50%→65% - Update MASTER_INVENTORY: frontend 135→139 - Update _INDEX.yml: total 14→15 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.3 KiB
5.3 KiB
06-DOCUMENTACION.md - OQI-005 Payments Advanced Components
Documentación Técnica
Componentes Creados
| Componente | LOC | Tipos | Descripción |
|---|---|---|---|
| StripeElementsWrapper | 220 | 1 | Foundation PCI-DSS |
| InvoicePreview | 350 | 4 | Vista previa factura |
| RefundRequestModal | 480 | 3 | Modal reembolsos |
| RefundList | 450 | 2 | Historial reembolsos |
| Total | 1500 | 10 |
API de Componentes
StripeElementsWrapper
interface StripeConfig {
publicKey: string;
locale?: 'en' | 'es' | 'auto';
appearance?: 'stripe' | 'night' | 'flat';
}
interface StripeElementsWrapperProps {
config: StripeConfig;
children: React.ReactNode;
}
// Uso
<StripeElementsWrapper config={{ publicKey: 'pk_test_...' }}>
<PaymentForm />
</StripeElementsWrapper>
// HOC
const WrappedComponent = withStripeElements(MyComponent, config);
// Hook
const isAvailable = useStripeAvailable();
InvoicePreview
interface InvoiceLineItem {
id: string;
description: string;
quantity: number;
unitPrice: number;
total: number;
}
interface InvoiceDiscount {
code?: string;
description: string;
type: 'percentage' | 'fixed';
value: number;
amount: number;
}
interface InvoiceTax {
name: string;
rate: number;
amount: number;
}
interface InvoicePreviewData {
invoiceNumber?: string;
items: InvoiceLineItem[];
subtotal: number;
discounts?: InvoiceDiscount[];
taxes?: InvoiceTax[];
total: number;
currency?: string;
periodStart?: string;
periodEnd?: string;
notes?: string;
}
interface InvoicePreviewProps {
data: InvoicePreviewData;
onConfirm?: () => void;
onCancel?: () => void;
confirmLabel?: string;
cancelLabel?: string;
isLoading?: boolean;
showActions?: boolean;
}
RefundRequestModal
type RefundReason =
| 'duplicate'
| 'fraudulent'
| 'customer_request'
| 'product_issue'
| 'other';
interface RefundEligibility {
eligible: boolean;
maxAmount: number;
reason?: string;
daysRemaining?: number;
}
interface RefundRequestData {
transactionId: string;
amount: number;
reason: RefundReason;
explanation: string;
}
interface RefundRequestModalProps {
isOpen: boolean;
onClose: () => void;
transactionId: string;
transactionAmount: number;
transactionDate: string;
eligibility: RefundEligibility;
onSubmit: (data: RefundRequestData) => Promise<void>;
currency?: string;
}
RefundList
type RefundStatus =
| 'pending'
| 'processing'
| 'completed'
| 'failed'
| 'cancelled';
interface Refund {
id: string;
transactionId: string;
amount: number;
currency: string;
status: RefundStatus;
reason: string;
explanation?: string;
createdAt: string;
processedAt?: string;
failureReason?: string;
}
interface RefundListProps {
refunds: Refund[];
totalCount: number;
currentPage: number;
pageSize: number;
onPageChange: (page: number) => void;
onStatusFilter?: (status: RefundStatus | 'all') => void;
selectedStatus?: RefundStatus | 'all';
isLoading?: boolean;
onRefundClick?: (refund: Refund) => void;
}
Integración con Backend
Endpoints Requeridos
| Endpoint | Método | Componente |
|---|---|---|
/api/payments/stripe/config |
GET | StripeElementsWrapper |
/api/invoices/preview |
POST | InvoicePreview |
/api/refunds/eligibility/:txId |
GET | RefundRequestModal |
/api/refunds |
POST | RefundRequestModal |
/api/refunds |
GET | RefundList |
Ejemplo de Integración
// pages/payments/refunds.tsx
import { RefundList, RefundRequestModal } from '@/components/payments';
export default function RefundsPage() {
const [refunds, setRefunds] = useState<Refund[]>([]);
const [selectedTx, setSelectedTx] = useState<string | null>(null);
// Fetch refunds
useEffect(() => {
fetch('/api/refunds')
.then(res => res.json())
.then(data => setRefunds(data.refunds));
}, []);
return (
<>
<RefundList
refunds={refunds}
totalCount={100}
currentPage={1}
pageSize={10}
onPageChange={handlePageChange}
/>
{selectedTx && (
<RefundRequestModal
isOpen={true}
onClose={() => setSelectedTx(null)}
transactionId={selectedTx}
// ...other props
/>
)}
</>
);
}
Consideraciones de Seguridad
PCI-DSS Compliance
-
StripeElementsWrapper asegura que:
- Datos de tarjeta nunca tocan nuestros servidores
- Tokenización manejada por Stripe
- Comunicación directa cliente-Stripe
-
Recomendación: Migrar
PaymentMethodFormexistente para usarCardElementde Stripe Elements en lugar de inputs manuales.
Validaciones
- RefundRequestModal valida montos contra elegibilidad
- Explicación requerida para todas las solicitudes
- Estados de error manejados apropiadamente
Próximos Pasos
-
Backend Integration
- Implementar endpoints de refunds
- Configurar webhooks de Stripe para status updates
-
Frontend Enhancements
- Migrar PaymentMethodForm a Stripe Elements
- Agregar tests unitarios
- Implementar páginas de gestión de reembolsos
-
OQI-005 Remaining
- Progress actual: 65%
- Pendiente: Dispute management, Advanced billing