payments = $payments; $this->settings = $settings; } /** * An invoice for the list view. * * @since 0.1.0 * * @param array $invoice Invoice. * @return array */ public function summary( array $invoice ): array { $money = array( $this->settings, 'format_money' ); return array( 'id' => $invoice['id'], 'invoice_number' => $invoice['invoice_number'], 'customer_id' => $invoice['customer_id'], 'customer_name' => $invoice['customer_name'], 'customer_email' => $invoice['customer_email'], 'order_id' => $invoice['order_id'], 'type' => $invoice['type'], 'status' => $invoice['status'], 'is_overdue' => $invoice['is_overdue'], 'issue_date' => $invoice['issue_date'], 'due_date' => $invoice['due_date'], 'subtotal' => $invoice['subtotal'], 'discount_total' => $invoice['discount_total'], 'tax_total' => $invoice['tax_total'], 'credit_applied' => $invoice['credit_applied'], 'total' => $invoice['total'], 'amount_paid' => $invoice['amount_paid'], 'balance' => $invoice['balance'], 'total_formatted' => $money( $invoice['total'] ), 'balance_formatted' => $money( $invoice['balance'] ), 'paid_at' => $this->iso( $invoice['paid_at_gmt'] ), 'can_edit' => InvoiceRules::can_edit_details( $invoice ), 'can_issue' => InvoiceStatus::DRAFT === $invoice['status'], 'can_pay' => in_array( $invoice['status'], InvoiceStatus::open(), true ), 'can_cancel' => in_array( $invoice['status'], array( InvoiceStatus::DRAFT, InvoiceStatus::UNPAID, InvoiceStatus::PARTIALLY_PAID ), true ) && 0 === $invoice['amount_paid'], ); } /** * An invoice with lines and payments. * * @since 0.1.0 * * @param array $invoice Invoice with `items`. * @return array */ public function detail( array $invoice ): array { $money = array( $this->settings, 'format_money' ); $items = array_map( static function ( array $item ) use ( $money ) { return array( 'id' => $item['id'], 'description' => $item['description'], 'quantity' => $item['quantity'], 'unit_price' => $item['unit_price'], 'unit_formatted' => $money( $item['unit_price'] ), 'tax_rate_bp' => $item['tax_rate_bp'], 'tax_amount' => $item['tax_amount'], 'total' => $item['total'], 'total_formatted' => $money( $item['total'] ), 'related_type' => $item['related_type'], 'related_id' => $item['related_id'], 'period_start' => $item['period_start'], 'period_end' => $item['period_end'], ); }, $invoice['items'] ); $payments = array_map( array( $this, 'payment' ), $this->payments->for_invoice( $invoice['id'] ) ); return array_merge( $this->summary( $invoice ), array( 'notes' => $invoice['notes'], 'can_edit_lines' => InvoiceRules::can_edit_lines( $invoice ), 'can_delete' => InvoiceRules::can_delete( $invoice, count( $payments ) ), 'items' => $items, 'payments' => $payments, 'subtotal_formatted' => $money( $invoice['subtotal'] ), 'discount_formatted' => $money( $invoice['discount_total'] ), 'tax_formatted' => $money( $invoice['tax_total'] ), 'credit_formatted' => $money( $invoice['credit_applied'] ), 'paid_formatted' => $money( $invoice['amount_paid'] ), 'print_url' => InvoiceDocument::admin_url( $invoice['id'] ), 'public_url' => '' !== $invoice['public_token'] ? add_query_arg( 'hostkhata_invoice', $invoice['public_token'], home_url( '/' ) ) : '', ) ); } /** * A payment or refund. * * @since 0.1.0 * * @param array $payment Payment row. * @return array */ public function payment( array $payment ): array { $confirmed = 'payment' === $payment['type'] && 'completed' === $payment['status']; $refunded = $confirmed ? $this->payments->refunded_amount( $payment['id'] ) : 0; return array( 'id' => $payment['id'], 'invoice_id' => $payment['invoice_id'], 'invoice_number' => $payment['invoice_number'], 'customer_id' => $payment['customer_id'], 'customer_name' => $payment['customer_name'], 'type' => $payment['type'], 'gateway' => $payment['gateway'], 'status' => $payment['status'], 'amount' => $payment['amount'], 'amount_formatted' => $this->settings->format_money( $payment['amount'] ), 'transaction_id' => 'refund' === $payment['type'] ? '' : $payment['transaction_id'], 'sender_number' => $payment['sender_number'], 'note' => $payment['note'], 'recorded_by' => $payment['recorder_name'], 'created_at' => $this->iso( $payment['created_at_gmt'] ), 'refundable' => $confirmed ? $payment['amount'] - $refunded : 0, 'refundable_formatted' => $confirmed ? $this->settings->format_money( $payment['amount'] - $refunded ) : '', 'can_verify' => 'payment' === $payment['type'] && 'pending' === $payment['status'], ); } /** * Converts a UTC MySQL datetime to ISO 8601, or an empty string. * * @param string $gmt UTC datetime. * @return string */ private function iso( string $gmt ): string { return '' === $gmt || '0000-00-00 00:00:00' === $gmt ? '' : str_replace( ' ', 'T', $gmt ) . 'Z'; } }