row = $row; $meta = isset( $row['meta'] ) ? json_decode( (string) $row['meta'], true ) : null; $this->meta = is_array( $meta ) ? $meta : array(); } /** * Column value. * * @param string $key Column. * @return mixed */ public function get( $key ) { return isset( $this->row[ $key ] ) ? $this->row[ $key ] : null; } /** * ID. * * @return int */ public function id() { return (int) $this->row['id']; } /** * Public request number, e.g. R-1042. * * @return string */ public function number() { /** * Filters the request number shown to customers and in the admin. * * @param string $number Default "R-{id}". * @param Request $request Request. */ return (string) apply_filters( 'rtkt_request_number', 'R-' . $this->id(), $this ); } /** * Type: return | exchange | withdrawal. * * @return string */ public function type() { return (string) $this->row['type']; } /** * Is this an EU withdrawal? * * @return bool */ public function is_withdrawal() { return 'withdrawal' === $this->type(); } /** * Status. * * @return string */ public function status() { return (string) $this->row['status']; } /** * Whether the request is closed (no more actions except notes). * * @return bool */ public function is_closed() { return in_array( $this->status(), array( 'completed', 'rejected', 'cancelled' ), true ); } /** * Resolution the customer asked for: refund | credit | exchange. * * @return string */ public function resolution() { return (string) $this->row['resolution']; } /** * Order ID (0 for a withdrawal that didn't match an order). * * @return int */ public function order_id() { return (int) $this->row['order_id']; } /** * The order, if it still exists. * * @return \WC_Order|null */ public function order() { if ( ! $this->order_id() ) { return null; } $order = wc_get_order( $this->order_id() ); return $order instanceof \WC_Order ? $order : null; } /** * Customer user ID (0 for guests). * * @return int */ public function customer_id() { return (int) $this->row['customer_id']; } /** * Customer email. * * @return string */ public function email() { return (string) $this->row['email']; } /** * Customer name. * * @return string */ public function name() { return (string) $this->row['name']; } /** * Customer comment. * * @return string */ public function note() { return (string) $this->row['note']; } /** * Currency code. * * @return string */ public function currency() { return (string) $this->row['currency']; } /** * Value of the requested items (incl. tax, after discounts). * * @return float */ public function total() { return (float) $this->row['total']; } /** * Refunded so far. * * @return float */ public function refunded() { return (float) $this->row['refunded']; } /** * Store credit issued so far. * * @return float */ public function credited() { return (float) $this->row['credited']; } /** * Created (GMT, MySQL format). * * @return string */ public function created_gmt() { return (string) $this->row['created_at']; } /** * Created, Unix timestamp. * * @return int */ public function created_ts() { return (int) strtotime( $this->created_gmt() . ' UTC' ); } /** * Updated, Unix timestamp. * * @return int */ public function updated_ts() { return (int) strtotime( (string) $this->row['updated_at'] . ' UTC' ); } /** * Flags (comma separated in the row). * * @return string[] */ public function flags() { $flags = trim( (string) $this->row['flags'] ); return '' === $flags ? array() : array_values( array_filter( array_map( 'trim', explode( ',', $flags ) ) ) ); } /** * Has a flag. * * @param string $flag Flag key. * @return bool */ public function has_flag( $flag ) { return in_array( $flag, $this->flags(), true ); } /** * Meta value. * * @param string $key Key. * @param mixed $default Default. * @return mixed */ public function meta( $key, $default = null ) { return array_key_exists( $key, $this->meta ) ? $this->meta[ $key ] : $default; } /** * All meta. * * @return array */ public function all_meta() { return $this->meta; } /** * Item rows. * * @return array[] */ public function items() { if ( null === $this->items ) { $this->items = Requests::items( $this->id() ); } return $this->items; } /** * Does the customer have to post anything back? False when every item is * virtual or downloadable (a withdrawal from a download or a service is * simply refunded). Items whose product was deleted count as physical, * and so does a withdrawal described in words. * * @return bool */ public function needs_shipping_back() { $items = $this->items(); if ( ! $items ) { return true; } foreach ( $items as $item ) { $product = wc_get_product( (int) $item['variation_id'] ? (int) $item['variation_id'] : (int) $item['product_id'] ); if ( ! $product || ! ( $product->is_virtual() || $product->is_downloadable() ) ) { return true; } } /** * Filters whether a request needs items posted back. * * @param bool $needs False: everything is digital. * @param Request $request Request. */ return (bool) apply_filters( 'rtkt_request_needs_shipping_back', false, $this ); } /** * Number of units requested. * * @return int */ public function qty() { $qty = 0; foreach ( $this->items() as $item ) { $qty += (int) $item['qty']; } return $qty; } /** * Secret used in guest links to this request: tied to the order key, so * nobody without the order email can build one. * * @return string */ public function access_token() { // A random secret saved with the request, so links already emailed keep // working when staff later link the request to an order. $secret = (string) $this->meta( 'secret', '' ); if ( '' === $secret ) { $order = $this->order(); $secret = $order ? $order->get_order_key() : $this->email(); } return substr( hash_hmac( 'sha256', 'rtkt-request|' . $this->id() . '|' . $secret . '|' . $this->created_gmt(), wp_salt( 'auth' ) ), 0, 32 ); } /** * Raw row (exports, tests). * * @return array */ public function to_array() { $row = $this->row; $row['meta'] = $this->meta; return $row; } }