JezK
Edit File: Payment.php
<?php namespace Bookly\Lib\Entities; use Bookly\Lib; use Bookly\Lib\DataHolders\Booking as DataHolders; class Payment extends Lib\Base\Entity { const TYPE_LOCAL = 'local'; const TYPE_FREE = 'free'; const TYPE_PAYPAL = 'paypal'; const TYPE_STRIPE = 'stripe'; const TYPE_CLOUD_STRIPE = 'cloud_stripe'; const TYPE_AUTHORIZENET = 'authorize_net'; const TYPE_2CHECKOUT = '2checkout'; const TYPE_PAYUBIZ = 'payu_biz'; const TYPE_PAYULATAM = 'payu_latam'; const TYPE_PAYSON = 'payson'; const TYPE_MOLLIE = 'mollie'; /** @deprecated Bookly 27.5 use TYPE_SQUARE */ const TYPE_CLOUD_SQUARE = 'cloud_square'; const TYPE_SQUARE = 'cloud_square'; const TYPE_WORLDPAY = 'worldpay'; const TYPE_WOOCOMMERCE = 'woocommerce'; const STATUS_COMPLETED = 'completed'; const STATUS_PENDING = 'pending'; const STATUS_REJECTED = 'rejected'; const STATUS_REFUNDED = 'refunded'; const PAY_DEPOSIT = 'deposit'; const PAY_IN_FULL = 'in_full'; const ITEM_APPOINTMENT = 'appointment'; const ITEM_PACKAGE = 'package'; const ITEM_GIFT_CARD = 'gift_card'; const ITEM_ADJUSTMENT = 'adjustment'; const ITEM_EVENT_ATTENDEE = 'event_attendee'; /** @var int */ protected $coupon_id; /** @var int */ protected $gift_card_id; /** @var string */ protected $type; /** @var float */ protected $total; /** @var float */ protected $tax = 0; /** @var float */ protected $paid; /** @var float */ protected $child_paid = 0; /** @var float */ protected $gateway_price_correction; /** @var string */ protected $paid_type = self::PAY_IN_FULL; /** @var string */ protected $status = self::STATUS_COMPLETED; /** @var string */ protected $token; /** @var string */ protected $details; /** @var int */ protected $order_id; /** @var int */ protected $customer_id; /** @var int */ protected $parent_id; /** @var string */ protected $ref_id; /** @var string */ protected $invoice_id; /** @var string */ protected $created_at; /** @var string */ protected $updated_at; /** @var Lib\DataHolders\Details\Payment */ protected $details_data; protected static $table = 'bookly_payments'; protected $loggable = true; protected static $schema = array( 'id' => array( 'format' => '%d' ), 'coupon_id' => array( 'format' => '%d', 'reference' => array( 'entity' => 'Coupon', 'namespace' => '\BooklyCoupons\Lib\Entities', 'required' => 'bookly-addon-coupons' ) ), 'gift_card_id' => array( 'format' => '%d', 'reference' => array( 'entity' => 'GiftCard', 'namespace' => '\BooklyGiftCards\Lib\Entities', 'required' => 'bookly-addon-gift-cards' ) ), 'type' => array( 'format' => '%s' ), 'total' => array( 'format' => '%f' ), 'tax' => array( 'format' => '%f' ), 'paid' => array( 'format' => '%f' ), 'child_paid' => array( 'format' => '%f' ), 'paid_type' => array( 'format' => '%s' ), 'gateway_price_correction' => array( 'format' => '%f' ), 'status' => array( 'format' => '%s' ), 'token' => array( 'format' => '%s' ), 'details' => array( 'format' => '%s' ), 'order_id' => array( 'format' => '%d', 'reference' => array( 'entity' => 'Order' ) ), 'customer_id' => array( 'format' => '%d', 'reference' => array( 'entity' => 'Customer' ) ), 'parent_id' => array( 'format' => '%d', 'reference' => array( 'entity' => 'Payment' ) ), 'ref_id' => array( 'format' => '%s' ), 'invoice_id' => array( 'format' => '%s' ), 'created_at' => array( 'format' => '%s' ), 'updated_at' => array( 'format' => '%s' ), ); /** * Get display name for given payment type. * * @param string $type * @return string */ public static function typeToString( $type ) { switch ( $type ) { case self::TYPE_PAYPAL: return 'PayPal'; case self::TYPE_LOCAL: return __( 'Local', 'bookly-responsive-appointment-booking-tool' ); case self::TYPE_STRIPE: return 'Stripe'; case self::TYPE_CLOUD_STRIPE: return 'Stripe Cloud'; case self::TYPE_SQUARE: return 'Square'; case self::TYPE_AUTHORIZENET: return 'Authorize.Net'; case self::TYPE_2CHECKOUT: return '2Checkout'; case self::TYPE_PAYUBIZ: return 'PayUbiz'; case self::TYPE_PAYULATAM: return 'PayU Latam'; case self::TYPE_PAYSON: return 'Payson'; case self::TYPE_MOLLIE: return 'Mollie'; case self::TYPE_FREE: return __( 'Free', 'bookly-responsive-appointment-booking-tool' ); case self::TYPE_WOOCOMMERCE: return 'WooCommerce'; case self::TYPE_WORLDPAY: return 'Worldpay'; default: return ''; } } /** * Get image for given payment type. * * @param string $type * @return array */ public static function typeToImage( $type ) { $height = '50px'; if ( $type === self::TYPE_LOCAL ) { $src = plugins_url( 'frontend/resources/images/wallet2.svg', Lib\Plugin::getMainFile() ); } else { $src = Lib\Proxy\Shared::preparePaymentImage( plugins_url( 'frontend/resources/images/card.svg', Lib\Plugin::getMainFile() ), $type ); } return compact( 'src', 'height' ); } /** * @param string $type * @return string */ public static function typeToProduct( $type ) { switch ( $type ) { case self::TYPE_CLOUD_STRIPE: return Lib\Cloud\Account::PRODUCT_STRIPE; default: return ''; } } /** * Get all types * * @return string[] */ public static function getTypes() { return array( self::TYPE_LOCAL, self::TYPE_2CHECKOUT, self::TYPE_PAYPAL, self::TYPE_AUTHORIZENET, self::TYPE_STRIPE, self::TYPE_CLOUD_STRIPE, self::TYPE_PAYUBIZ, self::TYPE_PAYULATAM, self::TYPE_PAYSON, self::TYPE_MOLLIE, self::TYPE_SQUARE, self::TYPE_FREE, self::TYPE_WOOCOMMERCE, ); } /** * Get status of payment. * * @param string $status * @return string */ public static function statusToString( $status ) { $caption = ''; switch ( $status ) { case self::STATUS_COMPLETED: $caption = __( 'Completed', 'bookly-responsive-appointment-booking-tool' ); break; case self::STATUS_PENDING: $caption = __( 'Pending', 'bookly-responsive-appointment-booking-tool' ); break; case self::STATUS_REJECTED: $caption = __( 'Rejected', 'bookly-responsive-appointment-booking-tool' ); break; case self::STATUS_REFUNDED: $caption = __( 'Refunded', 'bookly-responsive-appointment-booking-tool' ); break; } return $caption; } /** * @return Lib\DataHolders\Details\Payment */ public function getDetailsData() { if ( ! $this->details_data instanceof Lib\DataHolders\Details\Payment ) { $details = json_decode( $this->details ?: '[]', true ) ?: array(); $this->details_data = new Lib\DataHolders\Details\Payment( $details ); $this->details_data->setPayment( $this ); } return $this->details_data; } /** * Get invoice number, if not set - payment ID * * @return int */ public function getInvoiceNumber() { return $this->invoice_id === null ? $this->id : $this->invoice_id; } /** * @param DataHolders\Order $order * @param Lib\CartInfo $cart_info * @param array $extra * @return $this */ public function setDetailsFromOrder( DataHolders\Order $order, Lib\CartInfo $cart_info, $extra = array() ) { $this->details_data = new Lib\DataHolders\Details\Payment( array( 'gateway_ref_id' => isset( $extra['reference_id'] ) ? $extra['reference_id'] : null, ) ); $this->setOrderId( $order->getOrderId() ); $this->details_data->setOrder( $order, $cart_info ); return $this; } /** * Payment data for rendering payment details and invoice. * * @return array */ public function getPaymentData() { $details = $this->getDetailsData(); $data = $details->getData(); foreach ( $data['items'] as &$item ) { if ( $item['type'] === self::ITEM_APPOINTMENT && isset( $item['ca_id'] ) ) { $record = CustomerAppointment::query( 'ca' ) ->select( 'COALESCE(ca.compound_service_id, ca.collaborative_service_id, a.service_id) AS service_id, a.staff_id, s.title, st.full_name' ) ->leftJoin( 'Appointment', 'a', 'a.id = ca.appointment_id' ) ->leftJoin( 'Service', 's', 's.id = COALESCE(ca.compound_service_id, ca.collaborative_service_id, a.service_id)' ) ->leftJoin( 'Staff', 'st', 'st.id = a.staff_id' ) ->where( 'ca.id', $item['ca_id'] ) ->fetchRow(); if ( $record ) { if ( $record['service_id'] ) { $service = new Service( array( 'id' => $record['service_id'], 'title' => $record['title'] ) ); $item['service_name'] = $service->getTranslatedTitle(); } if ( $record['staff_id'] ) { $staff = new Staff( array( 'id' => $record['staff_id'], 'full_name' => $record['full_name'] ) ); $item['staff_name'] = $staff->getTranslatedName(); } } } } // Item discounts foreach ( $data['items'] as &$item ) { $discounts = array(); if ( isset( $item['discounts'] ) ) { foreach ( $item['discounts'] as $discount ) { if ( $discount['discount'] > 0 || $discount['deduction'] > 0 ) { $discounts[] = $discount; } } } $item['discounts'] = $discounts; } // Order discounts $discounts = array(); if ( isset( $data['discounts'] ) ) { foreach ( $data['discounts'] as $discount ) { if ( $discount['discount'] > 0 || $discount['deduction'] > 0 ) { $discounts[] = $discount; } } } return array( 'payment' => array( 'id' => (int) $this->id, 'status' => $this->status, 'type' => $this->type, 'created_at' => $this->created_at, 'token' => $this->token, 'customer' => $details->getCustomerName(), 'items' => $data['items'], 'subtotal' => $data['subtotal'], 'group_discount' => isset ( $data['customer_group']['discount_format'] ) ? $data['customer_group']['discount_format'] : false, 'discounts' => $discounts, 'coupon' => $data['coupon'], 'gift_card' => isset( $data['gift_card'] ) ? $data['gift_card'] : null, 'price_correction' => $this->gateway_price_correction, 'gateway' => $this->getType(), 'gateway_ref_id' => isset ( $data['gateway_ref_id'] ) ? $data['gateway_ref_id'] : null, 'paid' => $this->paid, 'child_paid' => $this->child_paid, 'tax_paid' => $data['tax_paid'], 'child_tax_paid' => $data['child_tax_paid'], 'total' => $this->total, 'tax_total' => $this->tax, 'tax_in_price' => $data['tax_in_price'], 'from_backend' => (bool) ( isset( $data['from_backend'] ) ? $data['from_backend'] : false ), 'extras_multiply_nop' => (bool) ( isset ( $data['extras_multiply_nop'] ) ? $data['extras_multiply_nop'] : true ), 'tips' => (float) ( isset ( $data['tips'] ) ? $data['tips'] : 0 ), 'invoice_number' => $this->invoice_id === null ? $this->id : $this->invoice_id, ), 'adjustments' => $details->getValue( 'adjustments', array() ) ); } /** * Get HTML for payment info displayed in a popover in the edit appointment form * * @param float $paid * @param float $total * @param string $type * @param string $status * @return string */ public static function paymentInfo( $paid, $total, $type, $status ) { $result = Lib\Utils\Price::format( $paid ); if ( $paid != $total ) { $result = sprintf( __( '%s of %s', 'bookly-responsive-appointment-booking-tool' ), $result, Lib\Utils\Price::format( $total ) ); } $result .= sprintf( ' %s <span%s>%s</span>', self::typeToString( $type ), $status == self::STATUS_PENDING ? ' class="text-danger"' : '', self::statusToString( $status ) ); return $result; } /************************************************************************** * Entity Fields Getters & Setters * **************************************************************************/ /** * Gets coupon_id * * @return int */ public function getCouponId() { return $this->coupon_id; } /** * Sets coupon_id * * @param int $coupon_id * @return $this */ public function setCouponId( $coupon_id ) { $this->coupon_id = $coupon_id; return $this; } /** * @return int */ public function getGiftCardId() { return $this->gift_card_id; } /** * @param int $gift_card_id * @return Payment */ public function setGiftCardId( $gift_card_id ) { $this->gift_card_id = $gift_card_id; return $this; } /** * Gets type * * @return string */ public function getType() { return $this->type; } /** * Sets type * * @param string $type * @return $this */ public function setType( $type ) { $this->type = $type; return $this; } /** * Gets total * * @return float */ public function getTotal() { return $this->total; } /** * Sets total * * @param float $total * @return $this */ public function setTotal( $total ) { $this->total = $total; return $this; } /** * Gets tax * * @return float */ public function getTax() { return $this->tax; } /** * Sets tax * * @param float $tax * @return $this */ public function setTax( $tax ) { $this->tax = $tax; return $this; } /** * Gets paid * * @return float */ public function getPaid() { return $this->paid; } /** * Sets paid * * @param float $paid * @return $this */ public function setPaid( $paid ) { $this->paid = $paid; return $this; } /** * @return float */ public function getChildPaid() { return $this->child_paid; } /** * @param float $child_paid * @return Payment */ public function setChildPaid( $child_paid ) { $this->child_paid = $child_paid; return $this; } /** * Gets fee * * @return float */ public function getGatewayPriceCorrection() { return $this->gateway_price_correction; } /** * Sets fee * * @param float $gateway_price_correction * @return $this */ public function setGatewayPriceCorrection( $gateway_price_correction ) { $this->gateway_price_correction = $gateway_price_correction; return $this; } /** * Gets paid_type * * @return string */ public function getPaidType() { return $this->paid_type; } /** * Sets paid_type * * @param string $paid_type * @return $this */ public function setPaidType( $paid_type ) { $this->paid_type = $paid_type; return $this; } /** * Gets status * * @return string */ public function getStatus() { return $this->status; } /** * Sets status * * @param string $status * @return $this */ public function setStatus( $status ) { $this->status = $status; return $this; } /** * Gets token * * @return string */ public function getToken() { return $this->token; } /** * Sets token * * @param string $token * @return $this */ public function setToken( $token ) { $this->token = $token; return $this; } /** * @return int */ public function getOrderId() { return $this->order_id; } /** * @param int $order_id * @return Payment */ public function setOrderId( $order_id ) { $this->order_id = $order_id; return $this; } /** * @return int */ public function getCustomerId() { return $this->customer_id; } /** * @param int $customer_id * @return Payment */ public function setCustomerId( $customer_id ) { $this->customer_id = $customer_id; return $this; } /** * @return int */ public function getParentId() { return $this->parent_id; } /** * @param int $parent_id * @return Payment */ public function setParentId( $parent_id ) { $this->parent_id = $parent_id; return $this; } /** * @return string */ public function getInvoiceId() { return $this->invoice_id; } /** * @param string $invoice_id * @return Payment */ public function setInvoiceId( $invoice_id ) { $this->invoice_id = $invoice_id; return $this; } /** * Gets ref_id * * @return string */ public function getRefId() { return $this->ref_id; } /** * Sets ref_id * * @param string $ref_id * @return $this */ public function setRefId( $ref_id ) { $this->ref_id = $ref_id; return $this; } /** * Gets created_at * * @return string */ public function getCreatedAt() { return $this->created_at; } /** * Sets created_at * * @param string $created_at * @return $this */ public function setCreatedAt( $created_at ) { $this->created_at = $created_at; return $this; } /** * @param Lib\CartInfo $cart_info * @return $this */ public function setCartInfo( Lib\CartInfo $cart_info ) { $pay_now = $cart_info->getGateway() === self::TYPE_LOCAL ? 0 : $cart_info->getPayNow(); if ( $pay_now > 0 ) { $type = $cart_info->getGateway(); } else { $type = $cart_info->getSubtotal() + $cart_info->getDiscount() > 0 ? self::TYPE_LOCAL : self::TYPE_FREE; } $this ->setType( $type ) ->setStatus( self::STATUS_PENDING ) ->setTotal( $cart_info->getTotal() ) ->setPaid( $pay_now ) ->setGatewayPriceCorrection( $cart_info->getPriceCorrection() ) ->setPaidType( ( $cart_info->getPayFull() || $cart_info->getTotal() == $pay_now ) ? self::PAY_IN_FULL : self::PAY_DEPOSIT ) ->setTax( $cart_info->getTotalTax() ); return $this; } /** * Gets updated_at * * @return string */ public function getUpdatedAt() { return $this->updated_at; } /** * Sets updated_at * * @param string $updated_at * @return $this */ public function setUpdatedAt( $updated_at ) { $this->updated_at = $updated_at; return $this; } /************************************************************************** * Overridden Methods * **************************************************************************/ public function save() { if ( $this->getId() === null ) { $this ->setCreatedAt( current_time( 'mysql' ) ) ->setUpdatedAt( current_time( 'mysql' ) ); if ( Lib\Config::invoicesActive() && get_option( 'bookly_invoices_id_fill_gaps', 0 ) === '1' ) { $invoice_ids = self::query()->whereNot( 'invoice_id', null )->fetchCol( 'invoice_id' ); $invoice_ids = array_fill_keys( $invoice_ids, null ); $invoice_id = (int) get_option( 'bookly_invoices_id_start_number', 1 ); while ( array_key_exists( $invoice_id, $invoice_ids ) ) { $invoice_id++; } $this->setInvoiceId( $invoice_id ); } } elseif ( $this->getModified() ) { $this->setUpdatedAt( current_time( 'mysql' ) ); } // Generate new token if it is not set. if ( ! $this->getToken() ) { $this->setToken( Lib\Utils\Common::generateToken( get_class( $this ), 'token' ) ); } if ( $this->details_data !== null ) { $details_data = $this->details_data; if ( $customer = $details_data->getCustomer() ) { $this->setCustomerId( $customer->getId() ); } $this->details = json_encode( $this->details_data->getData() ); // optimization $this->details_data = null; } return parent::save(); } }