'edit_purchase_order', 'read_post' => 'read_purchase_order', 'delete_post' => 'delete_purchase_order', 'edit_posts' => 'edit_purchase_orders', 'edit_others_posts' => 'edit_others_purchase_orders', 'create_posts' => 'create_purchase_orders', 'delete_posts' => 'delete_purchase_orders', 'delete_other_posts' => 'delete_other_purchase_orders', ); /** * PurchaseOrders constructor * * @since 1.2.9 */ public function __construct() { // Set post type labels. $this->labels = array( 'name' => __( 'Purchase Orders', ATUM_TEXT_DOMAIN ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralContext 'singular_name' => _x( 'Purchase Order', self::POST_TYPE . ' post type singular name', ATUM_TEXT_DOMAIN ), 'add_new' => __( 'Add New PO', ATUM_TEXT_DOMAIN ), 'add_new_item' => __( 'Add New PO', ATUM_TEXT_DOMAIN ), 'edit' => __( 'Edit', ATUM_TEXT_DOMAIN ), 'edit_item' => __( 'Edit PO', ATUM_TEXT_DOMAIN ), 'new_item' => __( 'New PO', ATUM_TEXT_DOMAIN ), 'view' => __( 'View PO', ATUM_TEXT_DOMAIN ), 'view_item' => __( 'View PO', ATUM_TEXT_DOMAIN ), 'search_items' => __( 'Search POs', ATUM_TEXT_DOMAIN ), 'not_found' => __( 'No purchase orders found', ATUM_TEXT_DOMAIN ), 'not_found_in_trash' => __( 'No purchase orders found in trash', ATUM_TEXT_DOMAIN ), 'parent' => __( 'Parent purchase order', ATUM_TEXT_DOMAIN ), 'menu_name' => _x( 'Purchase Orders', 'Admin menu name', ATUM_TEXT_DOMAIN ), 'filter_items_list' => __( 'Filter purchase orders', ATUM_TEXT_DOMAIN ), 'items_list_navigation' => __( 'Purchase orders navigation', ATUM_TEXT_DOMAIN ), 'items_list' => __( 'Purchase orders list', ATUM_TEXT_DOMAIN ), ); // Set meta box labels. $this->metabox_labels = array( 'data' => __( 'PO Data', ATUM_TEXT_DOMAIN ), 'notes' => __( 'PO Notes', ATUM_TEXT_DOMAIN ), 'actions' => __( 'PO Actions', ATUM_TEXT_DOMAIN ), ); // Initialize. parent::__construct(); // Add item order. add_filter( 'atum/admin/menu_items_order', array( $this, 'add_item_order' ) ); // Add the "Purchase Orders" link to the ATUM's admin bar menu. add_filter( 'atum/admin/top_bar/menu_items', array( $this, 'add_admin_bar_link' ), 11 ); // Add the help tab to PO list page. add_action( 'load-edit.php', array( $this, 'add_help_tab' ) ); // Add pdf Purchase Order print. add_filter( 'atum/' . self::POST_TYPE . '/admin_order_actions', array( $this, 'add_generate_pdf' ), 10, 2 ); // Generate Purchase Order's PDF. add_action( 'wp_ajax_atum_order_pdf', array( $this, 'generate_order_pdf' ) ); // Add the hooks for the Purchase Price field. ProductDataMetaBoxes::get_instance()->purchase_price_hooks(); } /** * Displays the data meta box at Purchase Orders * * @since 1.2.9 * * @param \WP_Post $post */ public function show_data_meta_box( $post ) { $atum_order = $this->get_current_atum_order( $post->ID ); if ( ! is_a( $atum_order, 'Atum\PurchaseOrders\Models\PurchaseOrder' ) ) { return; } $atum_order_post = $atum_order->get_post(); $supplier = $atum_order->get_supplier(); $has_multiple_suppliers = $atum_order->has_multiple_suppliers(); $labels = $this->labels; wp_nonce_field( 'atum_save_meta_data', 'atum_meta_nonce' ); Helpers::load_view( 'meta-boxes/purchase-order/data', compact( 'atum_order', 'supplier', 'has_multiple_suppliers', 'atum_order_post', 'labels' ) ); } /** * Save the ATUM Order meta boxes * * @since 1.2.9 * * @param int $log_id */ public function save_meta_boxes( $log_id ) { if ( empty( $_POST['status'] ) || empty( $_POST['atum_meta_nonce'] ) ) { return; } if ( ! wp_verify_nonce( $_POST['atum_meta_nonce'], 'atum_save_meta_data' ) ) { return; } $log = $this->get_current_atum_order( $log_id ); if ( empty( $log ) ) { return; } $po_date = empty( $_POST['date'] ) ? current_time( 'timestamp', TRUE ) : strtotime( $_POST['date'] . ' ' . (int) $_POST['date_hour'] . ':' . (int) $_POST['date_minute'] . ':00' ); $po_date = date( 'Y-m-d H:i:s', $po_date ); $expected_at_location_date = empty( $_POST['expected_at_location_date'] ) ? current_time( 'timestamp', TRUE ) : strtotime( $_POST['expected_at_location_date'] . ' ' . (int) $_POST['expected_at_location_date_hour'] . ':' . (int) $_POST['expected_at_location_date_minute'] . ':00' ); $expected_at_location_date = date( 'Y-m-d H:i:s', $expected_at_location_date ); $multiple_suppliers = ( isset( $_POST['multiple_suppliers'] ) && 'yes' === $_POST['multiple_suppliers'] ) ? 'yes' : 'no'; $log->save_meta( array( '_status' => esc_attr( $_POST['status'] ), '_date_created' => $po_date, Suppliers::SUPPLIER_META_KEY => 'no' === $multiple_suppliers && isset( $_POST['supplier'] ) ? absint( $_POST['supplier'] ) : '', '_multiple_suppliers' => $multiple_suppliers, '_expected_at_location_date' => $expected_at_location_date, ) ); // Set the Log description as post content. $log->set_description( $_POST['description'] ); $log->save(); } /** * Customize the columns used in the ATUM Order's list table * * @since 1.2.9 * * @param array $existing_columns * * @return array */ public function add_columns( $existing_columns ) { $columns = array( 'cb' => $existing_columns['cb'], 'atum_order_title' => __( 'PO', ATUM_TEXT_DOMAIN ), 'date' => __( 'Date', ATUM_TEXT_DOMAIN ), 'status' => __( 'Status', ATUM_TEXT_DOMAIN ), 'supplier' => __( 'Supplier', ATUM_TEXT_DOMAIN ), 'expected_date' => __( 'Date Expected', ATUM_TEXT_DOMAIN ), 'total' => __( 'Total', ATUM_TEXT_DOMAIN ), 'actions' => __( 'Actions', ATUM_TEXT_DOMAIN ), ); return $columns; } /** * Output custom columns for ATUM Order's list table * * @since 1.2.9 * * @param string $column * * @return void */ public function render_columns( $column ) { global $post; $rendered = parent::render_columns( $column ); if ( $rendered ) { return; } $po = $this->get_current_atum_order( $post->ID ); switch ( $column ) { case 'supplier': $supplier = $po->get_supplier(); if ( $supplier ) { echo esc_html( $supplier->post_title ); } break; case 'expected_date': $expected_date = $po->get_expected_at_location_date(); if ( $expected_date ) { $expected_date = '' . date_i18n( 'Y-m-d', strtotime( $expected_date ) ) . ''; } echo $expected_date; // WPCS: XSS ok. break; } } /** * Specify custom bulk actions messages for the PO post type * * @since 1.2.9 * * @param array $bulk_messages * @param array $bulk_counts * * @return array */ public function bulk_post_updated_messages( $bulk_messages, $bulk_counts ) { $bulk_messages[ self::POST_TYPE ] = array( /* translators: the number of purchase orders updated */ 'updated' => _n( '%s PO updated.', '%s POs updated.', $bulk_counts['updated'], ATUM_TEXT_DOMAIN ), /* translators: the number of purchase orders locked */ 'locked' => _n( '%s PO not updated, somebody is editing it.', '%s POs not updated, somebody is editing them.', $bulk_counts['locked'], ATUM_TEXT_DOMAIN ), /* translators: the number of purchase orders deleted */ 'deleted' => _n( '%s PO permanently deleted.', '%s POs permanently deleted.', $bulk_counts['deleted'], ATUM_TEXT_DOMAIN ), /* translators: the number of purchase orders moved to the trash */ 'trashed' => _n( '%s PO moved to the Trash.', '%s POs moved to the Trash.', $bulk_counts['trashed'], ATUM_TEXT_DOMAIN ), /* translators: the number of purchase orders restored from the trash */ 'untrashed' => _n( '%s PO restored from the Trash.', '%s POs restored from the Trash.', $bulk_counts['untrashed'], ATUM_TEXT_DOMAIN ), ); return $bulk_messages; } /** * Change messages when a PO post type is updated * * @since 1.2.9 * * @param array $messages * * @return array */ public function post_updated_messages( $messages ) { global $post; $messages[ self::POST_TYPE ] = array( 0 => '', // Unused. Messages start at index 1. 1 => __( 'PO updated.', ATUM_TEXT_DOMAIN ), 2 => __( 'Custom field updated.', ATUM_TEXT_DOMAIN ), 3 => __( 'Custom field deleted.', ATUM_TEXT_DOMAIN ), 4 => __( 'PO updated.', ATUM_TEXT_DOMAIN ), /* translators: the PO's revision title */ 5 => isset( $_GET['revision'] ) ? sprintf( __( 'PO restored to revision from %s', ATUM_TEXT_DOMAIN ), wp_post_revision_title( (int) $_GET['revision'], FALSE ) ) : FALSE, 6 => __( 'PO updated.', ATUM_TEXT_DOMAIN ), 7 => __( 'PO saved.', ATUM_TEXT_DOMAIN ), 8 => __( 'PO submitted.', ATUM_TEXT_DOMAIN ), /* translators: the purchase order's schedule date */ 9 => sprintf( __( 'PO scheduled for: %1$s.', ATUM_TEXT_DOMAIN ), date_i18n( __( 'M j, Y @ G:i', ATUM_TEXT_DOMAIN ), strtotime( $post->post_date ) ) ), 10 => __( 'PO draft updated.', ATUM_TEXT_DOMAIN ), 11 => __( 'PO updated and email sent.', ATUM_TEXT_DOMAIN ), ); return $messages; } /** * Add the Purchase Orders link to the ATUM's admin bar menu * * @since 1.2.9 * * @param array $atum_menus * * @return array */ public function add_admin_bar_link( $atum_menus ) { $atum_menus['purchase-orders'] = array( 'slug' => ATUM_SHORT_NAME . '-purchase-orders', 'title' => $this->labels['menu_name'], 'href' => 'edit.php?post_type=' . self::POST_TYPE, 'menu_order' => self::MENU_ORDER, ); return $atum_menus; } /** * Add the current item menu order * * @param array $items_order * * @return array */ public function add_item_order( $items_order ) { $items_order[] = array( 'slug' => 'edit.php?post_type=' . self::POST_TYPE, 'menu_order' => self::MENU_ORDER, ); return $items_order; } /** * Get the currently instantiated PO object (if any) or create a new one * * @since 1.2.9 * * @param int $post_id * * @return PurchaseOrder */ protected function get_current_atum_order( $post_id ) { if ( ! $this->po || $this->po->get_id() != $post_id ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison $this->po = new PurchaseOrder( $post_id ); } return $this->po; } /** * Get the available ATUM Order statuses * * @since 1.5.0 * * @return array */ public static function get_statuses() { return (array) apply_filters( 'atum/purchase_orders/statuses', array( ATUM_PREFIX . 'pending' => _x( 'Pending', 'ATUM Purchase Order status', ATUM_TEXT_DOMAIN ), ATUM_PREFIX . 'ordered' => _x( 'Ordered', 'ATUM Purchase Order status', ATUM_TEXT_DOMAIN ), ATUM_PREFIX . 'onthewayin' => _x( 'On the Way In', 'ATUM Purchase Order status', ATUM_TEXT_DOMAIN ), ATUM_PREFIX . 'receiving' => _x( 'Receiving', 'ATUM Purchase Order status', ATUM_TEXT_DOMAIN ), ATUM_PREFIX . 'received' => _x( 'Received', 'ATUM Purchase Order status', ATUM_TEXT_DOMAIN ), ) ); } /** * Add the help tab to the PO list page * * @since 1.3.0 */ public function add_help_tab() { $screen = get_current_screen(); if ( $screen && FALSE !== strpos( $screen->id, self::POST_TYPE ) ) { $help_tabs = array( array( 'name' => 'columns', 'title' => __( 'Columns', ATUM_TEXT_DOMAIN ), ), ); Helpers::add_help_tab( $help_tabs, $this ); } } /** * Display the help tabs' content * * @since 1.3.0 * * @param \WP_Screen $screen The current screen. * @param array $tab The current help tab. */ public function help_tabs_content( $screen, $tab ) { Helpers::load_view( 'help-tabs/purchase-orders/' . $tab['name'] ); } /** * Add generate pdf action to purchase orders column actions if user can export data * * @since 1.3.9 * * @param array $actions * @param PurchaseOrder $purchase_order * * @return mixed */ public function add_generate_pdf( $actions, $purchase_order ) { if ( AtumCapabilities::current_user_can( 'export_data' ) && ModuleManager::is_module_active( 'data_export' ) ) { $actions['pdf'] = array( 'url' => wp_nonce_url( admin_url( "admin-ajax.php?action=atum_order_pdf&atum_order_id={$purchase_order->get_id()}" ), 'atum-order-pdf' ), 'name' => __( 'Generate PDF', ATUM_TEXT_DOMAIN ), 'action' => 'pdf', 'target' => '_blank', 'icon' => '', ); } return $actions; } /** * Generate an Atum order pdf * * @since 1.3.9 */ public function generate_order_pdf() { $atum_order_id = absint( $_GET['atum_order_id'] ); if ( AtumCapabilities::current_user_can( 'export_data' ) && check_admin_referer( 'atum-order-pdf' ) && $atum_order_id ) { $po_export = new POExport( $atum_order_id ); try { $uploads = wp_upload_dir(); $temp_dir = $uploads['basedir'] . apply_filters( 'atum/purchase_orders/pdf_folder', '/atum' ); if ( ! is_dir( $temp_dir ) ) { // Try to create it. $success = mkdir( $temp_dir, 0777, TRUE ); // If can't create it, use default uploads folder. if ( ! $success || ! is_writable( $temp_dir ) ) { $temp_dir = $uploads['basedir']; } } $mpdf = new Mpdf( [ 'mode' => 'utf-8', 'format' => 'A4', 'tempDir' => $temp_dir, ] ); // Add support for non-Latin languages. $mpdf->useAdobeCJK = TRUE; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar $mpdf->autoScriptToLang = TRUE; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar $mpdf->autoLangToFont = TRUE; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar $mpdf->SetTitle( __( 'Purchase Order', ATUM_TEXT_DOMAIN ) ); $mpdf->default_available_fonts = $mpdf->available_unifonts; $css = $po_export->get_stylesheets(); foreach ( $css as $file ) { $stylesheet = file_get_contents( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions $mpdf->WriteHTML( $stylesheet, 1 ); } $mpdf->WriteHTML( $po_export->get_content() ); // Output a PDF file directly to the browser. wp_die( $mpdf->Output( "po-{$po_export->get_id()}.pdf", Destination::INLINE ) ); // WPCS: XSS ok. } catch ( MpdfException $e ) { wp_die( $e->getMessage() ); // WPCS: XSS ok. } } } }