diff --git a/backend/app/plugins/wiaas/includes/api/class-wiaas-rest-delivery-process-api.php b/backend/app/plugins/wiaas/includes/api/class-wiaas-rest-delivery-process-api.php index 5a8d493..e575199 100644 --- a/backend/app/plugins/wiaas/includes/api/class-wiaas-rest-delivery-process-api.php +++ b/backend/app/plugins/wiaas/includes/api/class-wiaas-rest-delivery-process-api.php @@ -1,6 +1,24 @@ 'GET', 'callback' => array(__CLASS__, 'get_next_actions_for_user'), ) ); - } + register_rest_route( self::$namespace, 'customer-acceptance/(?P\d+)', array( + 'methods' => 'GET', + 'callback' => array(__CLASS__, 'get_customer_acceptance'), + 'permission_callback' => 'is_user_logged_in' + ) ); + + register_rest_route( self::$namespace, 'customer-acceptance/(?P\d+)', array( + 'methods' => 'POST', + 'callback' => array(__CLASS__, 'submit_customer_acceptance'), + 'permission_callback' => 'is_user_logged_in' + ) ); + + register_rest_route( self::$namespace, 'customer-acceptance/(?P\d+)/upload-file' , array( + 'methods' => 'POST', + 'callback' => array(__CLASS__, 'upload_file'), + 'permission_callback' => 'is_user_logged_in' + ) ); + } public static function get_next_actions_for_user() { $current_user = wp_get_current_user(); @@ -62,4 +97,207 @@ class Wiass_REST_Delivery_Process_API { return $response; } + + public static function get_customer_acceptance(WP_REST_Request $request){ + $entry = GFAPI::get_entry($request['entry_id']); + if (is_wp_error($entry)){ + return self::generate_error('Customer acceptance entry not found', 404); + } + + $acceptance_documents = array(); + $uploaded_files = json_decode($entry[self::UPLOADED_FILES_FIELD_ID]); + + foreach($uploaded_files as $file_url){ + //example of decoded url : + //http://localhost/wp/index.php?gf-download=2018/08/rokovi-1535378841.docx&form-id=1&field-id=12&hash=1be6c30f0eeff93563b352d15fe459d5ded12ee06c2c8f36fed66b42dedf2534 + + $decoded_url = urldecode($file_url); + $url_parts = explode('?', $decoded_url); + $file_name_base_parts = explode('&', $url_parts[1]); + $file_name_parts = explode('/', $file_name_base_parts[0]); + $file_name_with_extension_parts = explode('.', $file_name_parts[2]); + + $acceptance_documents_entry = array( + 'name' => $file_name_with_extension_parts[0], + 'extension' => $file_name_with_extension_parts[1], + 'url' => $file_url + ); + array_push($acceptance_documents, $acceptance_documents_entry); + } + + $acceptance_status = 0; + if ($entry[self::ACCEPTANCE_STATUS_FIELD_ID]){ + $acceptance_status = ($entry[self::ACCEPTANCE_STATUS_FIELD_ID] === 'accept') ? 1 : -1; + } + + $result = array( + 'documents' => $acceptance_documents, + 'expiration' => $entry[self::EXPIRATION_DATE_FIELD_ID], + 'status' => $acceptance_status, + 'decline_reason' => $entry[self::DECLINE_REASON_FIELD_ID] + ); + + return new WP_REST_Response($result); + } + + public static function submit_customer_acceptance(WP_REST_Request $request){ + $entry = GFAPI::get_entry($request['entry_id']); + if (is_wp_error($entry)){ + return self::generate_error('Customer acceptance entry not found', 404); + } + + $status = $request['actionType']; + $reason = $request['declineReason']; + + if (!in_array($status, self::ACCEPTABLE_STATUS)){ + return self::generate_wiaas_response('ACCEPTANCE_STATUS_MISSING', 'error'); + } + + $installation_declined = ($status === self::DECLINE_STATUS_LABEL); + + $uploaded_files = json_decode($entry[self::UPLOADED_FILES_FIELD_ID]); + + if ($installation_declined && $reason === ''){ + return self::generate_wiaas_response('DECLINE_REASON_EMPTY', 'error'); + } + + if (!$installation_declined && (count($uploaded_files)===0)){ + return self::generate_wiaas_response('ACCEPTANCE_NOT_UPLOADED', 'error'); + } + + $entry[self::DECLINE_REASON_FIELD_ID] = $reason; + $entry[self::ACCEPTANCE_STATUS_FIELD_ID] = $status; + + if (!GFAPI::update_entry( $entry )){ + return self::generate_wiaas_response('INTERNAL_SERVER_ERROR', 'error'); + } + + //Check if step is already completed, to not submit again + $gf_api = new Gravity_Flow_API($entry['form_id']); + $current_step = $gf_api->get_current_step($entry); + if ($current_step->get_name() !== self::USER_INPUT_STEP_NAME){ + return self::generate_wiaas_response('ACCEPTANCE_STATUS_UPDATED', 'success'); + } + + if ( $current_step ) { + $current_step->purge_assignees(); + $current_step->update_step_status( 'complete' ); + } + $entry_id = $entry['id']; + $new_step_id = $current_step->get_id() + 1; + $new_step = $gf_api->get_step( $new_step_id, $entry ); + $feedback = sprintf( esc_html__( 'Sent to step: %s', 'gravityflow' ), $new_step->get_name() ); + $gf_api->add_timeline_note( $entry_id, $feedback ); + $gf_api->log_activity( 'workflow', 'sent_to_step', $gf_api->form_id, $entry_id, $step_id ); + gform_update_meta( $entry_id, 'workflow_final_status', 'pending' ); + $new_step->start(); + $gf_api->process_workflow( $entry_id ); + + + if ($installation_declined){ + return self::generate_wiaas_response('INSTALLATION_DECLINED', 'success'); + } + return self::generate_wiaas_response('INSTALLATION_ACCEPTED', 'success'); + } + + public static function upload_file(WP_REST_Request $request){ + $files = $request->get_file_params(); + if (!$files[self::FILE_KEY_NAME]){ + return self::generate_wiaas_response('NO_FILES_UPLOADED', 'error'); + } + + $entry = GFAPI::get_entry($request['entry_id']); + if (is_wp_error($entry)){ + return self::generate_error('Customer acceptance entry not found', 404); + } + + $form = GFAPI::get_form($entry['form_id']); + $form_upload_path = GFFormsModel::get_upload_path( $form['id'] ); + + $target_path = $form_upload_path . '/' . date('Y') . '/' . date('m') . '/'; + wp_mkdir_p( $target_path ); + GFCommon::recursive_add_index_file( $target_path ); + + $upload_file_field = GFAPI::get_field($form['id'], self::UPLOADED_FILES_FIELD_ID); + $file_name = sanitize_file_name($files[self::FILE_KEY_NAME]['name']); + $file_path_details = pathinfo($file_name); + + if ( GFCommon::file_name_has_disallowed_extension( $file_name ) ) { + return self::generate_wiaas_response('INVALID_FILE_ACCEPTANCE', 'error'); + } + $allowed_extensions = ! empty( $upload_file_field->allowedExtensions ) ? GFCommon::clean_extensions( explode( ',', strtolower( $upload_file_field->allowedExtensions ) ) ) : array(); + if ( ! empty( $allowed_extensions ) ) { + if ( ! GFCommon::match_file_extension( $file_name, $allowed_extensions ) ) { + return self::generate_wiaas_response('INVALID_FILE_ACCEPTANCE', 'error'); + } + } + + $new_file_name = $file_path_details['filename'] . '-' . time() . '.' . $file_path_details['extension']; + + // Bypasses security checks when running unit tests. + if ( defined( 'WP_TEST_IN_PROGRESS' ) && WP_TEST_IN_PROGRESS ) { + return self::generate_wiaas_response('FILE_UPLOADED', 'success'); + } + + if ( move_uploaded_file($files[self::FILE_KEY_NAME]['tmp_name'], $target_path . $new_file_name ) ) { + GFFormsModel::set_permissions( $target_path . $new_file_name ); + } else { + return self::generate_wiaas_response('INTERNAL_SERVER_ERROR', 'error'); + } + + //Extract path relative to the root + //Last 6 strings (excluding last empty) are path relative to the root + $path_parts = explode('/', $target_path); + + $relative_path = ''; + $i = count($path_parts) - self::PATH_PARTS_TO_EXTRACT; + while($i < count($path_parts)-1){ + $relative_path = $relative_path . $path_parts[$i] . '/'; + $i++; + } + + $file_url = self::BASE_NAME . $relative_path . $new_file_name; + $url_for_download = $upload_file_field->get_download_url($file_url); + + $uploaded_files = json_decode($entry[self::UPLOADED_FILES_FIELD_ID]); + + if ($uploaded_files === NULL){ + $uploaded_files = []; + } + array_push($uploaded_files, $url_for_download); + + $entry[self::UPLOADED_FILES_FIELD_ID] = json_encode($uploaded_files); + + if (GFAPI::update_entry( $entry )) { + return self::generate_wiaas_response('FILE_UPLOADED','success'); + } + + return self::generate_wiaas_response('NOT_UPLOADED', 'error'); + } + + //Helper function + private static function generate_error($message, $code = 500){ + $error = array( + 'status' => $code, + 'message' => $message, + ); + + $result = new WP_REST_Response($error); + $result->set_status($code); + return $result; + } + + private static function generate_wiaas_response($message, $code, $data = NULL){ + $response = array( + 'messages' => [ + array( + 'code' => $code, + 'message' => $message + ) + ], + 'data' => $data + ); + + return new WP_REST_Response($response); + } } \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/class-wiaas-delivery-process.php b/backend/app/plugins/wiaas/includes/class-wiaas-delivery-process.php index c3a526c..34b58c3 100644 --- a/backend/app/plugins/wiaas/includes/class-wiaas-delivery-process.php +++ b/backend/app/plugins/wiaas/includes/class-wiaas-delivery-process.php @@ -23,8 +23,33 @@ class Wiaas_Delivery_Process { add_filter( 'gform_entry_meta', array(__CLASS__, 'extend_gravity_form_entry_meta'), 10, 2 ); add_action( 'gravityflow_workflow_complete', array(__CLASS__, 'maybe_complete_parent_process_step'), 5, 3 ); + + add_action( 'gravityflow_workflow_complete', array(__CLASS__, 'maybe_complete_parent_order'), 10, 3 ); + + // Some temporary functions to make inbox page prettier + add_filter('gravityflow_inbox_submitter_name', array(__CLASS__, 'display_step_name_in_inbox'), 10, 3); + add_filter('gravityflow_approve_label_workflow_detail', array(__CLASS__, 'approval_step_approval_label'), 10, 2); + add_filter('gravityflow_reject_label_workflow_detail', array(__CLASS__, 'approval_step_reject_label'), 10, 2); } + public static function approval_step_approval_label($label, $step) { + if ($step->get_name() === 'Complete step') { + return esc_html__( 'Complete step', 'wiaas' ); + } + return $label; + } + + public static function approval_step_reject_label($label, $step) { + if ($step->get_name() === 'Complete step') { + return esc_html__( 'Cancel', 'wiaas' ); + } + return $label; + } + + public static function display_step_name_in_inbox($name, $entry, $form) { + return $entry['wiaas_delivery_step_name']; + } + /** * Registers our Delivery Process Step Type as available Gravity Flow Step Type */ @@ -34,6 +59,29 @@ class Wiaas_Delivery_Process { Gravity_Flow_Steps::register( new Wiaas_Delivery_Process_Step() ); } + /** + * Maybe complete parent order for completed delivery process + * @param $entry_id + * @param $form + */ + public static function maybe_complete_parent_order($entry_id, $form) { + $entry = GFAPI::get_entry($entry_id); + + $order_id = $entry['wiaas_delivery_order_id']; + + if (!isset($order_id)) { + return; + } + + $process_entry_id = get_post_meta($order_id, 'wiaas_delivery_process_entry_id', true); + + // order process entry completed, so complete order + if (absint($process_entry_id) === $entry_id) { + $order = wc_get_order($order_id); + $order->update_status('completed', 'Completed order delivery process.', true); + } + } + /** * Retrieves delivery process instance for order * @@ -134,6 +182,16 @@ class Wiaas_Delivery_Process { ), ); + $entry_meta[ 'wiaas_delivery_step_name' ] = array( + 'label' => 'Wiaas Delivery Step name', + 'is_numeric' => false, + 'update_entry_meta_callback' => null, + 'is_default_column' => false, // this column will be displayed by default on the entry list + 'filter' => array( + 'operators' => array( 'is' ), + ), + ); + return $entry_meta; } diff --git a/backend/app/plugins/wiaas/includes/class-wiaas-order.php b/backend/app/plugins/wiaas/includes/class-wiaas-order.php index b8fa3ff..06387ed 100644 --- a/backend/app/plugins/wiaas/includes/class-wiaas-order.php +++ b/backend/app/plugins/wiaas/includes/class-wiaas-order.php @@ -18,8 +18,19 @@ class Wiaas_Order { add_filter('woocommerce_rest_prepare_shop_order_object', array(__CLASS__, 'transform_rest_order'), 999, 3); add_filter('woocommerce_rest_orders_prepare_object_query', array( __CLASS__, 'wiaas_prepare_rest_orders_query'), 10, 2); + + add_filter('woocommerce_new_order_note_data', array( __CLASS__, 'update_new_order_comment_date'), 10, 3); } + public static function update_new_order_comment_date($comment_data, $order_data) { + $user = wp_get_current_user(); + + $comment_data['comment_author'] = $user->display_name; + $comment_data['comment_author_email'] = $user->user_email; + + return $comment_data; + } + /** * Assignees order to corresponding user organization when order is created. * @@ -94,6 +105,8 @@ class Wiaas_Order { $data = self::_append_commercial_lead_info($data, $order, $request); $data = self::_append_wiaas_order_details($data, $order, $request); + + $data = self::_append_order_comments($data, $order, $request); $response->set_data($data); @@ -126,6 +139,7 @@ class Wiaas_Order { private static function _append_commercial_lead_info($data, $order, $request) { $data['commercial_lead'] = array( + 'id' => 1, 'name' => 'Coor Service Management', 'phone' => '123456789', 'email' => 'rikard@co-ideation.com' @@ -228,6 +242,34 @@ class Wiaas_Order { return $data; } + + /** Append order comments if single order is requested + * @param $data + * @param $order + * @param $request + */ + private static function _append_order_comments($data, $order, $request) { + + if (isset($request['id'])) { + $current_user = wp_get_current_user(); + + $comments = $order->get_customer_order_notes(); + + $data['comments'] = array(); + + foreach ($comments as $comment) { + $data['comments'][] = array( + 'id' => $comment->comment_ID, + 'content' => $comment->comment_content, + 'username' => $comment->comment_author, + 'date' => $comment->comment_date, + 'is_owner' => $comment->comment_author === $current_user->display_name, + ); + } + } + + return $data; + } } Wiaas_Order::init(); diff --git a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_customer_acceptance_form.json b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_customer_acceptance_form.json index 0b7fe6b..659e050 100644 --- a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_customer_acceptance_form.json +++ b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_customer_acceptance_form.json @@ -1,387 +1,524 @@ { - "0": { - "title": "DELIVERY ACTION TYPE: Customer acceptance", - "description": "The customer must accept the implementation before further actions can be taken. If the customer isn't satisfied, the problems or discrepancies must be fixed in order to gen an acceptance.", - "labelPlacement": "top_label", - "descriptionPlacement": "below", - "button": { - "type": "text", - "text": "Submit", - "imageUrl": "" - }, - "fields": [ - { - "type": "workflow_user", - "id": 2, - "label": "customer-id", - "adminLabel": "customer-id", - "isRequired": false, - "size": "medium", - "errorMessage": "", - "visibility": "administrative", - "inputs": null, - "choices": [ - ], - "formId": 10, - "description": "", - "allowsPrepopulate": true, - "inputMask": false, - "inputMaskValue": "", - "inputType": "", - "labelPlacement": "", - "descriptionPlacement": "", - "subLabelPlacement": "", - "placeholder": "", - "cssClass": "", - "inputName": "customer-id", - "noDuplicates": false, - "defaultValue": "", - "conditionalLogic": "", - "failed_validation": "", - "productField": "", - "multipleFiles": false, - "maxFiles": "", - "calculationFormula": "", - "calculationRounding": "", - "enableCalculation": "", - "disableQuantity": false, - "displayAllCategories": false, - "useRichTextEditor": false, - "displayOnly": "", - "enablePrice": "", - "gravityflowUsersRoleFilter": "" - }, - { - "type": "date", - "id": 6, - "label": "Actual date", - "adminLabel": "", - "isRequired": false, - "size": "medium", - "errorMessage": "", - "visibility": "visible", - "inputs": null, - "dateType": "datepicker", - "calendarIconType": "none", - "formId": 10, - "description": "", - "allowsPrepopulate": false, - "inputMask": false, - "inputMaskValue": "", - "inputType": "", - "labelPlacement": "", - "descriptionPlacement": "", - "subLabelPlacement": "", - "placeholder": "", - "cssClass": "", - "inputName": "", - "noDuplicates": false, - "defaultValue": "", - "choices": "", - "conditionalLogic": "", - "calendarIconUrl": "", - "dateFormat": "ymd_dash", - "productField": "", - "multipleFiles": false, - "maxFiles": "", - "calculationFormula": "", - "calculationRounding": "", - "enableCalculation": "", - "disableQuantity": false, - "displayAllCategories": false, - "useRichTextEditor": false, - "displayOnly": "" - }, - { - "type": "fileupload", - "id": 7, - "label": "Acceptance document", - "adminLabel": "", - "isRequired": false, - "size": "medium", - "errorMessage": "", - "visibility": "visible", - "inputs": null, - "formId": 10, - "description": "Upload your acceptance document", - "allowsPrepopulate": false, - "inputMask": false, - "inputMaskValue": "", - "inputType": "", - "labelPlacement": "", - "descriptionPlacement": "", - "subLabelPlacement": "", - "placeholder": "", - "cssClass": "", - "inputName": "", - "noDuplicates": false, - "defaultValue": "", - "choices": "", - "conditionalLogic": "", - "maxFileSize": "", - "maxFiles": "", - "multipleFiles": false, - "allowedExtensions": "", - "productField": "", - "calculationFormula": "", - "calculationRounding": "", - "enableCalculation": "", - "disableQuantity": false, - "displayAllCategories": false, - "useRichTextEditor": false, - "displayOnly": "" - } - ], - "version": "2.3.2", - "id": 10, - "useCurrentUserAsAuthor": true, - "postContentTemplateEnabled": false, - "postTitleTemplateEnabled": false, - "postTitleTemplate": "", - "postContentTemplate": "", - "lastPageButton": null, - "pagination": null, - "firstPageCssClass": null, - "confirmations": [ - { - "id": "5b5f75f7494b7", - "name": "Default Confirmation", - "isDefault": true, - "type": "message", - "message": "Thanks for contacting us! We will get in touch with you shortly.", - "url": "", - "pageId": "", - "queryString": "" - } - ], - "notifications": [ - { - "id": "5b5f75f748cee", - "to": "{admin_email}", - "name": "Admin Notification", - "event": "form_submission", - "toType": "email", - "subject": "New submission from {form_title}", - "message": "{all_fields}" - } - ], - "feeds": { - "gravityflow": [ - { - "id": "22", - "form_id": "10", - "is_active": "1", - "feed_order": "0", - "meta": { - "step_name": "Upload acceptance file", - "description": "", - "step_type": "user_input", - "step_highlight": "0", - "step_highlight_type": "color", - "step_highlight_color": "#dd3333", - "feed_condition_conditional_logic": "0", - "feed_condition_conditional_logic_object": [], - "scheduled": "0", - "schedule_type": "delay", - "schedule_date": "", - "schedule_delay_offset": "", - "schedule_delay_unit": "hours", - "schedule_date_field_offset": "0", - "schedule_date_field_offset_unit": "hours", - "schedule_date_field_before_after": "after", - "type": "select", - "assignees": [ - "role|administrator", - "assignee_user_field|2" - ], - "editable_fields": [ - "5" - ], - "routing": "", - "assignee_policy": "any", - "highlight_editable_fields_enabled": "0", - "highlight_editable_fields_class": "green-triangle", - "instructionsEnable": "0", - "instructionsValue": "", - "display_fields_mode": "selected_fields", - "display_fields_selected": [ - "5" - ], - "default_status": "hidden", - "note_mode": "not_required", - "assignee_notification_enabled": "0", - "assignee_notification_from_name": "", - "assignee_notification_from_email": "{admin_email}", - "assignee_notification_reply_to": "", - "assignee_notification_bcc": "", - "assignee_notification_subject": "Upload order acceptance file", - "assignee_notification_message": "A new entry requires your input.", - "assignee_notification_disable_autoformat": "0", - "resend_assignee_emailEnable": "0", - "resend_assignee_emailValue": "7", - "resend_assignee_email_repeatEnable": "0", - "resend_assignee_email_repeatValue": "3", - "in_progress_notification_enabled": "0", - "in_progress_notification_type": "select", - "in_progress_notification_routing": [ - { - "assignee": "user_id|2", - "fieldId": "0", - "operator": "is", - "value": "", - "type": "" - } - ], - "in_progress_notification_from_name": "", - "in_progress_notification_from_email": "{admin_email}", - "in_progress_notification_reply_to": "", - "in_progress_notification_bcc": "", - "in_progress_notification_subject": "", - "in_progress_notification_message": "Entry {entry_id} has been updated and remains in progress.", - "in_progress_notification_disable_autoformat": "0", - "complete_notification_enabled": "0", - "complete_notification_type": "select", - "complete_notification_routing": [ - { - "assignee": "user_id|2", - "fieldId": "0", - "operator": "is", - "value": "", - "type": "" - } - ], - "complete_notification_from_name": "", - "complete_notification_from_email": "{admin_email}", - "complete_notification_reply_to": "", - "complete_notification_bcc": "", - "complete_notification_subject": "", - "complete_notification_message": "Entry {entry_id} has been updated completing the step.", - "complete_notification_disable_autoformat": "0", - "confirmation_messageEnable": "0", - "confirmation_messageValue": "Thank you.", - "expiration": "0", - "expiration_type": "delay", - "expiration_date": "", - "expiration_delay_offset": "7", - "expiration_delay_unit": "days", - "expiration_date_field_offset": "0", - "expiration_date_field_offset_unit": "hours", - "expiration_date_field_before_after": "after", - "status_expiration": "expired", - "destination_expired": "next", - "destination_complete": "next" - }, - "addon_slug": "gravityflow", - "event_type": null + "0": { + "title": "DELIVERY ACTION TYPE: Customer acceptance", + "description": "The customer must accept the implementation before further actions can be taken. If the customer isn't satisfied, the problems or discrepancies must be fixed in order to gen an acceptance.", + "labelPlacement": "top_label", + "descriptionPlacement": "below", + "button": { + "type": "text", + "text": "Submit", + "imageUrl": "" }, - { - "id": "30", - "form_id": "10", - "is_active": "1", - "feed_order": "0", - "meta": { - "step_name": "Approve customer acceptance", - "description": "", - "step_type": "approval", - "step_highlight": "0", - "step_highlight_type": "color", - "step_highlight_color": "#dd3333", - "feed_condition_conditional_logic": "0", - "feed_condition_conditional_logic_object": [], - "scheduled": "0", - "schedule_type": "delay", - "schedule_date": "", - "schedule_delay_offset": "", - "schedule_delay_unit": "hours", - "schedule_date_field_offset": "0", - "schedule_date_field_offset_unit": "hours", - "schedule_date_field_before_after": "after", - "type": "select", - "assignees": [ - "role|administrator" - ], - "routing": [ - { - "assignee": "user_id|2", - "fieldId": "0", - "operator": "is", - "value": "", - "type": "" - } - ], - "assignee_policy": "any", - "instructionsEnable": "0", - "instructionsValue": "Instructions: please review the values in the fields below and click on the Approve or Reject button", - "display_fields_mode": "all_fields", - "assignee_notification_enabled": "0", - "assignee_notification_from_name": "", - "assignee_notification_from_email": "{admin_email}", - "assignee_notification_reply_to": "", - "assignee_notification_bcc": "", - "assignee_notification_subject": "", - "assignee_notification_message": "A new entry is pending your approval. Please check your Workflow Inbox.", - "assignee_notification_disable_autoformat": "0", - "resend_assignee_emailEnable": "0", - "resend_assignee_emailValue": "7", - "resend_assignee_email_repeatEnable": "0", - "resend_assignee_email_repeatValue": "3", - "rejection_notification_enabled": "0", - "rejection_notification_type": "select", - "rejection_notification_routing": [ - { - "assignee": "user_id|2", - "fieldId": "0", - "operator": "is", - "value": "", - "type": "" - } - ], - "rejection_notification_from_name": "", - "rejection_notification_from_email": "{admin_email}", - "rejection_notification_reply_to": "", - "rejection_notification_bcc": "", - "rejection_notification_subject": "", - "rejection_notification_message": "Entry {entry_id} has been rejected", - "rejection_notification_disable_autoformat": "0", - "approval_notification_enabled": "0", - "approval_notification_type": "select", - "approval_notification_routing": [ - { - "assignee": "user_id|2", - "fieldId": "0", - "operator": "is", - "value": "", - "type": "" - } - ], - "approval_notification_from_name": "", - "approval_notification_from_email": "{admin_email}", - "approval_notification_reply_to": "", - "approval_notification_bcc": "", - "approval_notification_subject": "", - "approval_notification_message": "Entry {entry_id} has been approved", - "approval_notification_disable_autoformat": "0", - "revertEnable": "0", - "revertValue": "22", - "note_mode": "not_required", - "expiration": "0", - "expiration_type": "delay", - "expiration_date": "", - "expiration_delay_offset": "", - "expiration_delay_unit": "hours", - "expiration_date_field_offset": "0", - "expiration_date_field_offset_unit": "hours", - "expiration_date_field_before_after": "after", - "status_expiration": "rejected", - "destination_expired": "next", - "destination_rejected": "22", - "destination_approved": "next" - }, - "addon_slug": "gravityflow", - "event_type": null + "fields": [ + { + "type": "workflow_user", + "id": 2, + "label": "customer-id", + "adminLabel": "customer-id", + "isRequired": false, + "size": "medium", + "errorMessage": "", + "visibility": "administrative", + "inputs": null, + "choices": [ + ], + "formId": 1, + "description": "", + "allowsPrepopulate": true, + "inputMask": false, + "inputMaskValue": "", + "inputType": "", + "labelPlacement": "", + "descriptionPlacement": "", + "subLabelPlacement": "", + "placeholder": "", + "cssClass": "", + "inputName": "customer-id", + "noDuplicates": false, + "defaultValue": "", + "conditionalLogic": "", + "failed_validation": "", + "productField": "", + "multipleFiles": false, + "maxFiles": "", + "calculationFormula": "", + "calculationRounding": "", + "enableCalculation": "", + "disableQuantity": false, + "displayAllCategories": false, + "useRichTextEditor": false, + "displayOnly": "", + "enablePrice": "", + "gravityflowUsersRoleFilter": "" + }, + { + "type": "date", + "id": 6, + "label": "Actual date", + "adminLabel": "", + "isRequired": false, + "size": "medium", + "errorMessage": "", + "visibility": "visible", + "inputs": null, + "dateType": "datepicker", + "calendarIconType": "none", + "formId": 1, + "description": "", + "allowsPrepopulate": false, + "inputMask": false, + "inputMaskValue": "", + "inputType": "", + "labelPlacement": "", + "descriptionPlacement": "", + "subLabelPlacement": "", + "placeholder": "", + "cssClass": "", + "inputName": "", + "noDuplicates": false, + "defaultValue": "", + "choices": "", + "conditionalLogic": "", + "calendarIconUrl": "", + "dateFormat": "ymd_dash", + "productField": "", + "multipleFiles": false, + "maxFiles": "", + "calculationFormula": "", + "calculationRounding": "", + "enableCalculation": "", + "disableQuantity": false, + "displayAllCategories": false, + "useRichTextEditor": false, + "displayOnly": "" + }, + { + "type": "radio", + "id": 8, + "label": "acceptance", + "adminLabel": "", + "isRequired": false, + "size": "medium", + "errorMessage": "", + "visibility": "visible", + "inputs": null, + "choices": [ + { + "text": "not-accepted", + "value": "not-accepted", + "isSelected": true, + "price": "" + }, + { + "text": "accept", + "value": "accept", + "isSelected": false, + "price": "" + }, + { + "text": "decline", + "value": "decline", + "isSelected": false, + "price": "" + } + ], + "formId": 1, + "description": "", + "allowsPrepopulate": false, + "inputMask": false, + "inputMaskValue": "", + "inputType": "", + "labelPlacement": "", + "descriptionPlacement": "", + "subLabelPlacement": "", + "placeholder": "", + "cssClass": "", + "inputName": "", + "noDuplicates": false, + "defaultValue": "", + "conditionalLogic": "", + "productField": "", + "enableOtherChoice": "", + "enablePrice": "", + "multipleFiles": false, + "maxFiles": "", + "calculationFormula": "", + "calculationRounding": "", + "enableCalculation": "", + "disableQuantity": false, + "displayAllCategories": false, + "useRichTextEditor": false, + "displayOnly": "" + }, + { + "type": "date", + "id": 9, + "label": "Expiration date", + "adminLabel": "", + "isRequired": false, + "size": "medium", + "errorMessage": "", + "visibility": "visible", + "inputs": null, + "dateType": "datepicker", + "calendarIconType": "none", + "formId": 1, + "description": "", + "allowsPrepopulate": false, + "inputMask": false, + "inputMaskValue": "", + "inputType": "", + "labelPlacement": "", + "descriptionPlacement": "", + "subLabelPlacement": "", + "placeholder": "", + "cssClass": "", + "inputName": "", + "noDuplicates": false, + "defaultValue": "", + "choices": "", + "conditionalLogic": "", + "calendarIconUrl": "", + "dateFormat": "ymd_dash", + "productField": "", + "multipleFiles": false, + "maxFiles": "", + "calculationFormula": "", + "calculationRounding": "", + "enableCalculation": "", + "disableQuantity": false, + "displayAllCategories": false, + "useRichTextEditor": false, + "displayOnly": "" + }, + { + "type": "text", + "id": 10, + "label": "Reason", + "adminLabel": "", + "isRequired": false, + "size": "medium", + "errorMessage": "", + "visibility": "visible", + "inputs": null, + "formId": 1, + "description": "", + "allowsPrepopulate": false, + "inputMask": false, + "inputMaskValue": "", + "inputType": "", + "labelPlacement": "", + "descriptionPlacement": "", + "subLabelPlacement": "", + "placeholder": "", + "cssClass": "", + "inputName": "", + "noDuplicates": false, + "defaultValue": "", + "choices": "", + "conditionalLogic": "", + "productField": "", + "enablePasswordInput": "", + "maxLength": "", + "multipleFiles": false, + "maxFiles": "", + "calculationFormula": "", + "calculationRounding": "", + "enableCalculation": "", + "disableQuantity": false, + "displayAllCategories": false, + "useRichTextEditor": false, + "displayOnly": "", + "enablePrice": "" + }, + { + "type": "fileupload", + "id": 12, + "label": "File", + "adminLabel": "", + "isRequired": false, + "size": "medium", + "errorMessage": "", + "visibility": "visible", + "inputs": null, + "formId": 1, + "description": "Upload customer acceptance file", + "allowsPrepopulate": false, + "inputMask": false, + "inputMaskValue": "", + "inputType": "", + "labelPlacement": "", + "descriptionPlacement": "", + "subLabelPlacement": "", + "placeholder": "", + "cssClass": "", + "inputName": "", + "noDuplicates": false, + "defaultValue": "", + "choices": "", + "conditionalLogic": "", + "maxFileSize": "", + "maxFiles": "", + "multipleFiles": true, + "allowedExtensions": "pdf,docx,doc,xlsx,xls,odt,ods,jpg,png,jpeg", + "productField": "", + "calculationFormula": "", + "calculationRounding": "", + "enableCalculation": "", + "disableQuantity": false, + "displayAllCategories": false, + "useRichTextEditor": false + } + ], + "version": "2.3.2", + "id": 1, + "useCurrentUserAsAuthor": true, + "postContentTemplateEnabled": false, + "postTitleTemplateEnabled": false, + "postTitleTemplate": "", + "postContentTemplate": "", + "lastPageButton": null, + "pagination": null, + "firstPageCssClass": null, + "is_active": "1", + "date_created": "2018-08-15 20:30:18", + "is_trash": "0", + "confirmations": [ + { + "id": "5b5f75f7494b7", + "name": "Default Confirmation", + "isDefault": true, + "type": "message", + "message": "Thanks for contacting us! We will get in touch with you shortly.", + "url": "", + "pageId": "", + "queryString": "" + } + ], + "notifications": [ + { + "id": "5b5f75f748cee", + "to": "{admin_email}", + "name": "Admin Notification", + "event": "form_submission", + "toType": "email", + "subject": "New submission from {form_title}", + "message": "{all_fields}" + } + ], + "feeds": { + "gravityflow": [ + { + "id": "1", + "form_id": "1", + "is_active": "1", + "feed_order": "0", + "meta": { + "step_name": "Upload acceptance file", + "description": "", + "step_type": "user_input", + "step_highlight": "0", + "step_highlight_type": "color", + "step_highlight_color": "#dd3333", + "feed_condition_conditional_logic": "0", + "feed_condition_conditional_logic_object": [], + "scheduled": "0", + "schedule_type": "delay", + "schedule_date": "", + "schedule_delay_offset": "", + "schedule_delay_unit": "hours", + "schedule_date_field_offset": "0", + "schedule_date_field_offset_unit": "hours", + "schedule_date_field_before_after": "after", + "schedule_date_field": "6", + "type": "select", + "assignees": [ + "role|administrator", + "assignee_user_field|2" + ], + "routing": "", + "assignee_policy": "any", + "highlight_editable_fields_enabled": "0", + "highlight_editable_fields_class": "green-triangle", + "instructionsEnable": "0", + "instructionsValue": "", + "display_fields_mode": "selected_fields", + "default_status": "hidden", + "note_mode": "not_required", + "assignee_notification_enabled": "0", + "assignee_notification_from_name": "", + "assignee_notification_from_email": "{admin_email}", + "assignee_notification_reply_to": "", + "assignee_notification_bcc": "", + "assignee_notification_subject": "Upload order acceptance file", + "assignee_notification_message": "A new entry requires your input.", + "assignee_notification_disable_autoformat": "0", + "resend_assignee_emailEnable": "0", + "resend_assignee_emailValue": "7", + "resend_assignee_email_repeatEnable": "0", + "resend_assignee_email_repeatValue": "3", + "in_progress_notification_enabled": "0", + "in_progress_notification_type": "select", + "in_progress_notification_routing": [ + { + "assignee": "user_id|2", + "fieldId": "0", + "operator": "is", + "value": "", + "type": "" + } + ], + "in_progress_notification_from_name": "", + "in_progress_notification_from_email": "{admin_email}", + "in_progress_notification_reply_to": "", + "in_progress_notification_bcc": "", + "in_progress_notification_subject": "", + "in_progress_notification_message": "Entry {entry_id} has been updated and remains in progress.", + "in_progress_notification_disable_autoformat": "0", + "complete_notification_enabled": "0", + "complete_notification_type": "select", + "complete_notification_routing": [ + { + "assignee": "user_id|2", + "fieldId": "0", + "operator": "is", + "value": "", + "type": "" + } + ], + "complete_notification_from_name": "", + "complete_notification_from_email": "{admin_email}", + "complete_notification_reply_to": "", + "complete_notification_bcc": "", + "complete_notification_subject": "", + "complete_notification_message": "Entry {entry_id} has been updated completing the step.", + "complete_notification_disable_autoformat": "0", + "confirmation_messageEnable": "0", + "confirmation_messageValue": "Thank you.", + "expiration": "0", + "expiration_type": "date_field", + "expiration_date": "", + "expiration_delay_offset": "7", + "expiration_delay_unit": "days", + "expiration_date_field_offset": "0", + "expiration_date_field_offset_unit": "hours", + "expiration_date_field_before_after": "after", + "expiration_date_field": "9", + "status_expiration": "expired", + "destination_expired": "2", + "destination_complete": "next" + }, + "addon_slug": "gravityflow", + "event_type": null + }, + { + "id": "2", + "form_id": "1", + "is_active": "1", + "feed_order": "0", + "meta": { + "step_name": "Approve customer acceptance", + "description": "", + "step_type": "approval", + "step_highlight": "0", + "step_highlight_type": "color", + "step_highlight_color": "#dd3333", + "feed_condition_conditional_logic": "0", + "feed_condition_conditional_logic_object": [], + "scheduled": "0", + "schedule_type": "delay", + "schedule_date": "", + "schedule_delay_offset": "", + "schedule_delay_unit": "hours", + "schedule_date_field_offset": "0", + "schedule_date_field_offset_unit": "hours", + "schedule_date_field_before_after": "after", + "type": "select", + "assignees": [ + "role|administrator" + ], + "routing": [ + { + "assignee": "user_id|2", + "fieldId": "0", + "operator": "is", + "value": "", + "type": "" + } + ], + "assignee_policy": "any", + "instructionsEnable": "0", + "instructionsValue": "Instructions: please review the values in the fields below and click on the Approve or Reject button", + "display_fields_mode": "all_fields", + "assignee_notification_enabled": "0", + "assignee_notification_from_name": "", + "assignee_notification_from_email": "{admin_email}", + "assignee_notification_reply_to": "", + "assignee_notification_bcc": "", + "assignee_notification_subject": "", + "assignee_notification_message": "A new entry is pending your approval. Please check your Workflow Inbox.", + "assignee_notification_disable_autoformat": "0", + "resend_assignee_emailEnable": "0", + "resend_assignee_emailValue": "7", + "resend_assignee_email_repeatEnable": "0", + "resend_assignee_email_repeatValue": "3", + "rejection_notification_enabled": "0", + "rejection_notification_type": "select", + "rejection_notification_routing": [ + { + "assignee": "user_id|2", + "fieldId": "0", + "operator": "is", + "value": "", + "type": "" + } + ], + "rejection_notification_from_name": "", + "rejection_notification_from_email": "{admin_email}", + "rejection_notification_reply_to": "", + "rejection_notification_bcc": "", + "rejection_notification_subject": "", + "rejection_notification_message": "Entry {entry_id} has been rejected", + "rejection_notification_disable_autoformat": "0", + "approval_notification_enabled": "0", + "approval_notification_type": "select", + "approval_notification_routing": [ + { + "assignee": "user_id|2", + "fieldId": "0", + "operator": "is", + "value": "", + "type": "" + } + ], + "approval_notification_from_name": "", + "approval_notification_from_email": "{admin_email}", + "approval_notification_reply_to": "", + "approval_notification_bcc": "", + "approval_notification_subject": "", + "approval_notification_message": "Entry {entry_id} has been approved", + "approval_notification_disable_autoformat": "0", + "revertEnable": "0", + "revertValue": 1, + "note_mode": "not_required", + "expiration": "0", + "expiration_type": "delay", + "expiration_date": "", + "expiration_delay_offset": "", + "expiration_delay_unit": "hours", + "expiration_date_field_offset": "0", + "expiration_date_field_offset_unit": "hours", + "expiration_date_field_before_after": "after", + "status_expiration": "rejected", + "destination_expired": "next", + "destination_rejected": 1, + "destination_approved": "next" + }, + "addon_slug": "gravityflow", + "event_type": null + } + ] } - ] - } - }, - "version": "2.3.2.6" + }, + "version": "2.3.2" } \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_manual_form.json b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_manual_form.json index f975650..cbca857 100644 --- a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_manual_form.json +++ b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_manual_form.json @@ -30,7 +30,7 @@ "text": "wpUser" } ], - "formId": 12, + "formId": 4, "description": "", "allowsPrepopulate": true, "inputMask": false, @@ -71,7 +71,7 @@ "inputs": null, "dateType": "datepicker", "calendarIconType": "calendar", - "formId": 12, + "formId": 4, "description": "", "allowsPrepopulate": false, "inputMask": false, @@ -102,7 +102,7 @@ } ], "version": "2.3.2", - "id": 12, + "id": 4, "useCurrentUserAsAuthor": true, "postContentTemplateEnabled": false, "postTitleTemplateEnabled": false, @@ -111,17 +111,9 @@ "lastPageButton": null, "pagination": null, "firstPageCssClass": null, - "notifications": [ - { - "id": "5b5f9ebc520f3", - "to": "{admin_email}", - "name": "Admin Notification", - "event": "form_submission", - "toType": "email", - "subject": "New submission from {form_title}", - "message": "{all_fields}" - } - ], + "is_active": "1", + "date_created": "2018-08-09 15:36:00", + "is_trash": "0", "confirmations": [ { "id": "5b5f9ebc52a80", @@ -134,11 +126,22 @@ "queryString": "" } ], + "notifications": [ + { + "id": "5b5f9ebc520f3", + "to": "{admin_email}", + "name": "Admin Notification", + "event": "form_submission", + "toType": "email", + "subject": "New submission from {form_title}", + "message": "{all_fields}" + } + ], "feeds": { "gravityflow": [ { - "id": "27", - "form_id": "12", + "id": "6", + "form_id": "4", "is_active": "1", "feed_order": "0", "meta": { @@ -245,5 +248,5 @@ ] } }, - "version": "2.3.2.6" + "version": "2.3.2" } \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_schedule_meeting.json b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_schedule_meeting.json index 4c9bff0..be4ebb0 100644 --- a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_schedule_meeting.json +++ b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_schedule_meeting.json @@ -30,7 +30,7 @@ "text": "wpUser" } ], - "formId": 13, + "formId": 2, "description": "", "allowsPrepopulate": true, "inputMask": false, @@ -70,7 +70,7 @@ "inputs": null, "dateType": "datepicker", "calendarIconType": "calendar", - "formId": 13, + "formId": 2, "description": "", "allowsPrepopulate": false, "inputMask": false, @@ -111,7 +111,7 @@ "inputs": null, "dateType": "datepicker", "calendarIconType": "calendar", - "formId": 13, + "formId": 2, "description": "", "allowsPrepopulate": false, "inputMask": false, @@ -141,7 +141,7 @@ } ], "version": "2.3.2", - "id": 13, + "id": 2, "useCurrentUserAsAuthor": true, "postContentTemplateEnabled": false, "postTitleTemplateEnabled": false, @@ -150,6 +150,9 @@ "lastPageButton": null, "pagination": null, "firstPageCssClass": null, + "is_active": "1", + "date_created": "2018-08-09 15:35:59", + "is_trash": "0", "confirmations": [ { "id": "5b60b12baa00e", @@ -176,8 +179,8 @@ "feeds": { "gravityflow": [ { - "id": "31", - "form_id": "13", + "id": "3", + "form_id": "2", "is_active": "1", "feed_order": "0", "meta": { @@ -286,8 +289,8 @@ "event_type": null }, { - "id": "32", - "form_id": "13", + "id": "4", + "form_id": "2", "is_active": "1", "feed_order": "0", "meta": { @@ -377,7 +380,7 @@ "approval_notification_message": "Entry {entry_id} has been approved", "approval_notification_disable_autoformat": "0", "revertEnable": "0", - "revertValue": "31", + "revertValue": 3, "note_mode": "not_required", "expiration": "0", "expiration_type": "delay", @@ -390,7 +393,7 @@ "expiration_date_field": "4", "status_expiration": "rejected", "destination_expired": "next", - "destination_rejected": "31", + "destination_rejected": 3, "destination_approved": "complete" }, "addon_slug": "gravityflow", @@ -399,5 +402,5 @@ ] } }, - "version": "2.3.2.6" + "version": "2.3.2" } \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_validate_questionnaire_form.json b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_validate_questionnaire_form.json index 340ad0d..e5e55f1 100644 --- a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_validate_questionnaire_form.json +++ b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_action_validate_questionnaire_form.json @@ -30,7 +30,7 @@ "text": "wpUser" } ], - "formId": 9, + "formId": 3, "description": "", "allowsPrepopulate": true, "inputMask": false, @@ -71,7 +71,7 @@ "inputs": null, "dateType": "datepicker", "calendarIconType": "none", - "formId": 9, + "formId": 3, "description": "", "allowsPrepopulate": false, "inputMask": false, @@ -101,7 +101,7 @@ } ], "version": "2.3.2", - "id": 9, + "id": 3, "useCurrentUserAsAuthor": true, "postContentTemplateEnabled": false, "postTitleTemplateEnabled": false, @@ -110,17 +110,9 @@ "lastPageButton": null, "pagination": null, "firstPageCssClass": null, - "notifications": [ - { - "id": "5b5f68818822e", - "to": "{admin_email}", - "name": "Admin Notification", - "event": "form_submission", - "toType": "email", - "subject": "New submission from {form_title}", - "message": "{all_fields}" - } - ], + "is_active": "1", + "date_created": "2018-08-09 15:36:00", + "is_trash": "0", "confirmations": [ { "id": "5b5f688188e90", @@ -133,11 +125,22 @@ "queryString": "" } ], + "notifications": [ + { + "id": "5b5f68818822e", + "to": "{admin_email}", + "name": "Admin Notification", + "event": "form_submission", + "toType": "email", + "subject": "New submission from {form_title}", + "message": "{all_fields}" + } + ], "feeds": { "gravityflow": [ { - "id": "20", - "form_id": "9", + "id": "5", + "form_id": "3", "is_active": "1", "feed_order": "0", "meta": { @@ -257,5 +260,5 @@ ] } }, - "version": "2.3.2.6" + "version": "2.3.2" } \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_process_normal_delivery_form.json b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_process_normal_delivery_form.json index 997729c..7258d6f 100644 --- a/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_process_normal_delivery_form.json +++ b/backend/app/plugins/wiaas/includes/db-updates/data/delivery-forms/delivery_process_normal_delivery_form.json @@ -21,7 +21,7 @@ "visibility": "visible", "inputs": null, "numberFormat": "decimal_dot", - "formId": "11", + "formId": 5, "description": "", "allowsPrepopulate": true, "inputMask": false, @@ -71,7 +71,7 @@ "text": "wpUser" } ], - "formId": "11", + "formId": 5, "description": "", "allowsPrepopulate": true, "inputMask": false, @@ -102,7 +102,7 @@ } ], "version": "2.3.2.6", - "id": "11", + "id": 5, "useCurrentUserAsAuthor": true, "postContentTemplateEnabled": false, "postTitleTemplateEnabled": false, @@ -112,20 +112,8 @@ "pagination": null, "firstPageCssClass": null, "is_active": "1", - "date_created": "2018-07-30 20:53:56", + "date_created": "2018-08-09 15:36:00", "is_trash": "0", - "notifications": [ - { - "id": "5b5f7ae4baced", - "to": "{admin_email}", - "name": "Admin Notification", - "event": "form_submission", - "toType": "email", - "subject": "New submission from {form_title}", - "message": "{all_fields}", - "isActive": false - } - ], "confirmations": [ { "id": "5b5f7ae4bb79e", @@ -138,11 +126,23 @@ "queryString": "" } ], + "notifications": [ + { + "id": "5b5f7ae4baced", + "to": "{admin_email}", + "name": "Admin Notification", + "event": "form_submission", + "toType": "email", + "subject": "New submission from {form_title}", + "message": "{all_fields}", + "isActive": false + } + ], "feeds": { "gravityflow": [ { - "id": "28", - "form_id": "11", + "id": "7", + "form_id": "5", "is_active": "1", "feed_order": "0", "meta": { @@ -164,7 +164,7 @@ "schedule_date_field_before_after": "after", "instructionsEnable": "0", "instructionsValue": "", - "target_form_id": "9", + "target_form_id": 3, "store_new_entry_idEnable": "1", "new_entry_id_field": "6", "destination_complete": "next" @@ -173,8 +173,8 @@ "event_type": null }, { - "id": "33", - "form_id": "11", + "id": "8", + "form_id": "5", "is_active": "1", "feed_order": "0", "meta": { @@ -196,7 +196,7 @@ "schedule_date_field_before_after": "after", "instructionsEnable": "0", "instructionsValue": "", - "target_form_id": "12", + "target_form_id": 4, "store_new_entry_idEnable": "0", "new_entry_id_field": "", "destination_complete": "next" @@ -205,8 +205,8 @@ "event_type": null }, { - "id": "34", - "form_id": "11", + "id": "9", + "form_id": "5", "is_active": "1", "feed_order": "0", "meta": { @@ -228,7 +228,7 @@ "schedule_date_field_before_after": "after", "instructionsEnable": "0", "instructionsValue": "", - "target_form_id": "12", + "target_form_id": 4, "store_new_entry_idEnable": "0", "new_entry_id_field": "", "destination_complete": "next" @@ -237,8 +237,8 @@ "event_type": null }, { - "id": "29", - "form_id": "11", + "id": "10", + "form_id": "5", "is_active": "1", "feed_order": "0", "meta": { @@ -258,7 +258,7 @@ "schedule_date_field_offset": "0", "schedule_date_field_offset_unit": "hours", "schedule_date_field_before_after": "after", - "target_form_id": "10", + "target_form_id": 1, "store_new_entry_idEnable": "1", "new_entry_id_field": "7", "destination_complete": "next" @@ -267,8 +267,8 @@ "event_type": null }, { - "id": "36", - "form_id": "11", + "id": "11", + "form_id": "5", "is_active": "1", "feed_order": "0", "meta": { @@ -290,7 +290,7 @@ "schedule_date_field_before_after": "after", "instructionsEnable": "0", "instructionsValue": "", - "target_form_id": "12", + "target_form_id": 4, "store_new_entry_idEnable": "0", "new_entry_id_field": "", "destination_complete": "next", @@ -300,8 +300,8 @@ "event_type": null }, { - "id": "35", - "form_id": "11", + "id": "12", + "form_id": "5", "is_active": "1", "feed_order": "0", "meta": { @@ -323,7 +323,7 @@ "schedule_date_field_before_after": "after", "instructionsEnable": "0", "instructionsValue": "", - "target_form_id": "12", + "target_form_id": 4, "store_new_entry_idEnable": "0", "new_entry_id_field": "", "destination_complete": "next" @@ -334,5 +334,5 @@ ] } }, - "version": "2.3.2.6" + "version": "2.3.2" } \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/delivery-process/class-wiaas-delivery-process-step.php b/backend/app/plugins/wiaas/includes/delivery-process/class-wiaas-delivery-process-step.php index e4497c7..8c5b478 100644 --- a/backend/app/plugins/wiaas/includes/delivery-process/class-wiaas-delivery-process-step.php +++ b/backend/app/plugins/wiaas/includes/delivery-process/class-wiaas-delivery-process-step.php @@ -100,6 +100,7 @@ class Wiaas_Delivery_Process_Step extends Gravity_Flow_Step { 'form_id' => $this->target_form_id, 'wiaas_delivery_process_id' => $this->get_entry_id(), 'wiaas_delivery_order_id' => $entry['wiaas_delivery_order_id'], + 'wiaas_delivery_step_name' => $this->get_name(), ); $customer_id_value = null; diff --git a/backend/app/plugins/wiaas/tests/dummy-files/invalid-customer-acceptance.txt b/backend/app/plugins/wiaas/tests/dummy-files/invalid-customer-acceptance.txt new file mode 100644 index 0000000..b7534b8 --- /dev/null +++ b/backend/app/plugins/wiaas/tests/dummy-files/invalid-customer-acceptance.txt @@ -0,0 +1,27 @@ + +x\9C\AD[O\AF\E36\BF\E7S\E4\\E0\A5\FAc\C96\F0\CBK\98[\BB\D8C\D1\DBn \9D\B6\97\F9\FAK\91\92%Y\B4d\8F\DBA+&)\8A?\89\A4D=q\93\D7o\97\FF]\FC3\A3\B9\A9\EB\D0\C9\DBp\FD\EB?\97\FDp\FD\EFE\DCF +\FF]\D7\DF\FD~1榯\D6@-G \CFR!\E3\F5\B7.\AA\B37^J\F7\9C\BC\D4VC?\F4\B2\EB\F3w\9D\F0L\EF\A0\93\BD\B3v\E9\B1wd\C9;T\A6\D3\E2\D6o)\E3_\F2\CA\D0K^z\C7+C\EF\D6ʐ9\853\D2\FB\E7\C5X\A7o\AFo\E3\F5\F3\DF\D7_H\AF\9F\BF\FDrrzSw\A1\F0SO\C3]t\F8h&\F8\B0\A2\9F\F0\E77\F8}\98\C2\CF\C3$\C5]\8C\C0j\DC\D7<\BDɻxG6 \DF\F0\E3#\CA qr\FA\F5\F3\CB\E5\F9y\F9\89U\CC +\98+Ő\FBcz\B3\FE\F1\89\82\D2\EB\EE\A5\E9(\A4\F4\C4Z\8CRMâ\DD\D3\E9F\FE\98Íi\9Elk,\AF\AD\B1H\AD\DD`\E0S\D3`\D4U\DA\C5ʶC-Ԓ8\8B\A2\F1\CB\D2WO_|9\852\FF\E3L_\EF\F4\F5\88|Ú/g\D0\893\AD]ZOb9\95^\F8\E5l\ECZsdw)Iʜ\E9\E2\D5\FD\C8~$u\A5\CAz\E8\B6l\A9Fg\C5^va\C6F[\8EA\D5ڔ\B2\A3\85\B5\92sJ\9D +\EB\91 +\99\E9\92]f\BF>cx\92nj!\BD\93&\95"\A9[\D9S+\B7\A6\D9L'\B7F\AChc9\88\97P\B2\93Б[\91\E0|f\F9._R\E3; \F1?\FF\C3\F5t\E6\FA +Z_\AE\F2\FA\87\F7\A6\83\84\BE\BE^\8C\C4֟\D7\92f=\F8\C2>\D2c\ABJ\9Fc\A4\C7V\95\BE\D3\E0zlU\E9\E5\98\CA\C7V\95^\F4\A9|l\D5\E8\CD\D8\C1g\A0\A7V\95>\B3\A7i\DA\D3d\F64M{\9A̞\A6iO\93\D9\D34\EDi \BC$\E3\C5V\95^\F6\E9x\B1U\A5]:^l\D5\E8;\ADq\BCԪ\D2\F7c2^jU\E91\A8.\F4ت\CE@\D4:\FAȼA\EEO\EF3\82*\92R\B2\F1շ\AA Z\C6\EC\E4\ABo\D50\D1Z\B0Ug\A0\BCɏ\C1'.5\9FLy\9F\CDT(\C3 + \B69\94\8C0`k\C5PD\87^.\DET\F8 +\B1Hj\E7\E45\BA\ED"\96&\A7\EF\DC\ECV\9C\EA\D7y!Ob\86\E2\CDJLA\B4qOÖ8=V\9C\92\98\A9\80Cj\B72\943`)CM=\86\T\00\B4S\C7\E6\D4 +c\DDi\FB\BAՔ\98Q7x`\E4W\B5B\D8 #+\A5\DA?\86\C4\D4\FD`'Jy»\C1\E7\F8\AB +\B4#\90\88y +\B4\F8Db + \EF\F4\F6\E1d\DF~>\81\A8>`jIa\FD0\DE4H;\B6ж\A3[\DF+\CCi\A4\95=\FCQBx?}\FEQ\C1\9A\E9\D8z9\E3$\D4\F0\EC\F09]\FC\A9\815'r\94.\89s\A2\C9Wgn\DD\DA\DAi\009\89|ʗ\C2|&\B5v\B3\D2=jT\EB\A5:j\8B1|C\999\B58F#\9F\FEGj[\F9\88 ƥ[w\F8\D4N\D6+șƻ\E7ro\D4\E0\D4!.F\E5V\A4Q`\D5 +t<\BE%\DFQ|{\9EŗI\F8\8E\DBS\96\F0U\AA\9C\EC/\97l\BE\E4C\CDʒ\D5\C1\FA +U\E8\FD\9E\F0ީ\8A/8\AD\DAtf\DE\F4L\87 +W\A6zb\8E\DBXa\FBa\CE"\80\BBŕ\9D7U\E48\D4K\81\FF\92"\B4\DCVz\E0 f\9D\D5\E6>\D4\CB/\8D\8C[\93\95\90c\B9rYdi!=\B4\8Bl\F0B\C6e\E4 \A1\93:'>i\95.\C1r\FD\B5&\A7\9B\F5.^ߛn\B6`?< \CEN\82R)5\E0\88\CC\E8\F2ƕ\86\A9dK\ADPZ\93\E9u\97\FAW\84\B0\B3 38\DCٯIm\DC#\FA\E0 dmb\ADYt\B5G\B1 +]\A93\CDE]u\9C \D7A\C48[\9DDlk(c\B3\81Y\EB\CEs\A19!b\BD\8D޲A\B0\BE\83\E6Û\D9;RG\BC\D3\E4\\97v\DAZ)%\EBa\BB3\9D\9F\B5;'\B2ۙ\90\98^\AE\A3\87\8FM8\D3uO\86 +9\BA#\F90\FA{\96\ \8B\CBZ\80IVE\C0.d./rn\D8O\r\8D,\A3Tգ\86yF\B7\EBaԊ\AE\CFbV +܍\D8V>\9C\D5\E2\E0\92Ճ\E9\DE\F2\8Dߥ\E3\89\E0\E7F\B0\D9\EC#h\86\D3\F9<׹Kʼ݇\85\89?5\A08\93\CF&Y\D4\EE\EC\DC\88dD\B9<,\B32Jb\F8N\8B\E7\9D" e\E2^Jm n\8FA\00\C1Ji$\84%\F3a\88\B8\FC\F9$D\BC\C8\00Q=%7Z\95Y\81^\82 z8\D5\E7\F1#\A6\E1\DD\FE%\E4|\A0 (;Ȑ&u\92\ED\B5U\E8Z\CFL=f%\D7Q\CC\9DŬT\AA\99\BFɱ \CCf\DB\E0\8DG\CEc\A6\9C\E9\97߉:\DD;'\AB\8A˳\95?\9A\AA\83T\A8v\BB[\99\8E\87\A9\E4; +c\A0\B30\F1\83i$m\A2_\FB<\A2/k \99\F4\9C_r\DB<\82dxN\8E\F0\D5X)\AC\A6Kn\DCX'%\F3aИ\EEςƍhhv(\A3\BDM\9D\93\B7\B2\C6`\8D\E8в\81\m\D9J\FA}N\BE\8D\ABN\CFI\D6 w\80\B4\A9e#\DBQg\D0[\EC\FB\8E\D1K\D6\C33\9D\9FE\98\E9\8FY\A7N\DC\DDA\96\EC\BDh\BD4\91D'\F6&\F1\9B\85\FB\AE\D30\9B\96\C2%\B6\AA\85N-\96\8A\99\F2\AD*\BD\EC\B1J\E8\E9\B1U\A5\B1 \EC\9Ek\B4zt\87\95\81\9AZUz\9Bu\A9U\A57iQ\97ZUz\B0^ԞZUz\BC\83\B5\D0c\ABJ֋Elj\D5\E8՘ɩU\A5\D2"9\B5\AA\F4\99=UӞ*\B3\A7j\DASe\F6TM{\AA̞\AAiO\95\D9S5\ED\D9}"s\B5h\E8\A9Ug\A02\BD\00\B5\AA \BEL\EF\A8Ug\A02}`\C0V\9D\81\CA\F4~ Ԫ2\F82\BDg\A0V\9D\81\CA\F4\81\C16\C7\E0\CB\F4ɴ\90k\86"\E8\C1^+^\FB;\CA\F6\9C\C4S\85{N\E0\F1\D2=+\E5l\F1\BEj\BD\EF/\DFC2x[\F2\ED<:\B0Y\AAgHa0s\B1~cO_\97s\8DV\82\C2(\BC7\C3(X]\86\D1\C90\98\CEO\9E\B1\B2"\F7\ECu\A2wUקF \DE\D6\D0>yO\95 +N8ޫ\A1ӨZ\B0 +-\A7z\AD\8DY\C1|\A6\FB\B3\F8p"\F7\9E\EAi\F4f\FF\A6\98\96\DA#\96\94hk\96\D6e\E7P\B8m!Qv\BD\A7d\C7p\84\80\F2Ix+\C2XB^\85`Pɥ\F9\C0\AC:\F9\D2\889?\F9q\A5\A2@\EA\CFV{\B3P\89m\CA\F69\E6ጐ݇\D3thܟ\D6=\B3ۭ\D4\EE\95+\95\ED*㗒\F7]\A3a\F8\8EN-nL'\A7#r\FF\D42\CCf\F7\BB\CE\EC\E9FR\AD_\8D\B5N\C38Mܯ)\D9C\C3(pκ\FB\EF\D7l\C6\82\AE3Lu=^\C2\C8V\EA +\CA\EB3\CB\C2M\F8\CB\E8*\92\F8\ABF\93\ADqz\CF뷫\FA_\B2\93\E9\FC,\98\DCx\F6\9C\94\B9\BF\E3\D8߲+\88[\85\FC\B7x[\00+\9C\CE \E6\E9-\A9\99Tu^p\D7kZ.\B5\E4\DE;k\D6\C3X]\9FE\BA\B8\F7\CE\00\BB8O\F6"\E1\EAa\821G'u\B3Z\80\ABC\C0\F4\BD\F3\BE@\C9z\A6\F3\93\97\ECxvr\B4(\FD\EE\B1a\92\85K\A3K\ACK] \A4\9B\A5{ +\E1*\AEꞮ$\A4\85T\9Ft%!\B4\9A\C8U-\A0Ƣ\A6\F6R3\C5\E8p\E1\B5_4\F7[!\BA\BA\E3\B6\AA3\AC{\CB&k֣3\931Źy\C9 +\DC\E7\D4\C0\94\C8ػ\ADߗlW _\8DS\8E\86\83/U\AFߘ\F0\B8s\DEW\E3d:<\8A<\D3\F9Y\EC9\91{\83\83\E22u\BCP\FE~`N\F6\C9酖4\A3N\AFa\E2\CD \8C\FF\FD=ݭ\85\8B\85\CC.\8E\\CF\DFw\Rj\DF% +\86\EF(\BC\DC^\EA$\BC\9C\C8o=!WL\B6\9F\C6~\B7\\C2\D9Uz\EB\A9\C0>[\9DG\AF8q\EA(\83\B2\EC\FB\B2\89\92\F50\B4\DC^\EC$\B4սX\D7\CDĿ\8C\A8\E8\8A\E3B\93\FF\F8\A7\DCB/\C1\D0\D1:n\00\CA\E9\B1\FF\8FJ\F6èp\9B\AA\93\A8\94J\B5.\AF\A9";\F7\C7\CB\DArw\A1\F0\F4’\D5\C9\C3%^M\AA\E5\\F6L\E9ٲ\DF\FEč\97\BF6\nrk\94\AEf\C7=q\BBr{t\E4\8A՚\FD0r\E5\8E\E6$nk\85\9A\A8qɼ +~\A0 diff --git a/backend/app/plugins/wiaas/tests/dummy-files/valid-customer-acceptance.odt b/backend/app/plugins/wiaas/tests/dummy-files/valid-customer-acceptance.odt new file mode 100644 index 0000000..060cb8a Binary files /dev/null and b/backend/app/plugins/wiaas/tests/dummy-files/valid-customer-acceptance.odt differ diff --git a/backend/app/plugins/wiaas/tests/unit-tests/test-wiaas-rest-delivery-process-api.php b/backend/app/plugins/wiaas/tests/unit-tests/test-wiaas-rest-delivery-process-api.php index 726e865..7f48145 100644 --- a/backend/app/plugins/wiaas/tests/unit-tests/test-wiaas-rest-delivery-process-api.php +++ b/backend/app/plugins/wiaas/tests/unit-tests/test-wiaas-rest-delivery-process-api.php @@ -9,6 +9,15 @@ class Wiass_REST_Delivery_Process_Api_Test extends Wiaas_Unit_Test_Case { var $order_id, $api; + /** + * Test REST Server + * + * @var WP_REST_Server + */ + protected $server; + + protected $namespaced_route = '/wiaas'; + function setUp() { parent::setUp(); @@ -17,6 +26,41 @@ class Wiass_REST_Delivery_Process_Api_Test extends Wiaas_Unit_Test_Case { $this->order_id = $order->get_id(); wp_set_current_user(1); + + /** @var WP_REST_Server $wp_rest_server */ + global $wp_rest_server; + $this->server = $wp_rest_server = new \WP_REST_Server; + do_action( 'rest_api_init' ); + + $original_valid_customer_acceptance = __DIR__ . '/../dummy-files/valid-customer-acceptance.odt'; + $this->test_file_valid_customer_acceptance = '/tmp/valid-customer-acceptance.odt'; + copy( $original_valid_customer_acceptance, $this->test_file_valid_customer_acceptance ); + + $original_invalid_customer_acceptance = __DIR__ . '/../dummy-files/invalid-customer-acceptance.txt'; + $this->test_file_invalid_customer_acceptance = '/tmp/invalid-customer-acceptance.txt'; + copy( $original_invalid_customer_acceptance, $this->test_file_invalid_customer_acceptance ); + } + + function test_register_route() { + $routes = $this->server->get_routes(); + $this->assertArrayHasKey( $this->namespaced_route, $routes ); + } + + + function test_endpoints() { + $the_route = $this->namespaced_route; + $routes = $this->server->get_routes(); + foreach( $routes as $route => $route_config ) { + if( 0 === strpos( $the_route, $route ) ) { + $this->assertTrue( is_array( $route_config ) ); + foreach( $route_config as $i => $endpoint ) { + $this->assertArrayHasKey( 'callback', $endpoint ); + $this->assertArrayHasKey( 0, $endpoint[ 'callback' ], get_class( $this ) ); + $this->assertArrayHasKey( 1, $endpoint[ 'callback' ], get_class( $this ) ); + $this->assertTrue( is_callable( array( $endpoint[ 'callback' ][0], $endpoint[ 'callback' ][1] ) ) ); + } + } + } } /** @@ -49,4 +93,429 @@ class Wiass_REST_Delivery_Process_Api_Test extends Wiaas_Unit_Test_Case { $this->assertEquals($pending_step['status'], 'pending'); $this->assertNotEmpty($pending_step['step_action']); } + + /** + * @covers Wiass_REST_Delivery_Process_API::get_customer_acceptance + */ + function test_get_customer_acceptance_as_guest() { + wp_set_current_user(0); + + $request = new WP_REST_Request( 'GET', '/wiaas/customer-acceptance/99191991919191'); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertTrue($response->is_error()); + $this->assertEquals($response->get_status(), 401); + + $error_data = $response->as_error(); + $this->assertEquals($error_data->get_error_message(), 'Sorry, you are not allowed to do that.'); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::get_customer_acceptance + */ + function test_get_nonexisting_customer_acceptance() { + wp_set_current_user(1); + + $request = new WP_REST_Request( 'GET', '/wiaas/customer-acceptance/911919191919' ); //non existing entry ID + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertTrue($response->is_error()); + $this->assertEquals($response->get_status(), 404); + + $error_data = $response->as_error(); + $this->assertEquals($error_data->get_error_message(), 'Customer acceptance entry not found'); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::get_customer_acceptance + */ + function test_get_valid_customer_acceptance() { + wp_set_current_user(1); + + $customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry(); + $request = new WP_REST_Request( 'GET', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id ); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + + $this->assertTrue(is_array($response_data)); + $this->assertArrayHasKey('documents', $response_data); + $this->assertArrayHasKey('expiration', $response_data); + $this->assertArrayHasKey('status', $response_data); + $this->assertArrayHasKey('decline_reason', $response_data); + + $this->assertTrue(is_array($response_data['documents'])); + $uploaded_file = $response_data['documents'][0]; + $this->assertTrue(is_array($uploaded_file)); + $this->assertArrayHasKey('name', $uploaded_file); + $this->assertArrayHasKey('extension', $uploaded_file); + $this->assertArrayHasKey('url', $uploaded_file); + $this->assertEquals($uploaded_file['name'], 'file1'); + $this->assertEquals($uploaded_file['extension'], 'docx'); + $this->assertEquals($uploaded_file['url'], 'http://localhost/wp/index.php?gf-download=2018%2F08%2Ffile1.docx&form-id=1&field-id=12&hash=1be6c30f0eeff93563b352d15fe459d5ded12ee06c2c8f36fed66b42dedf2534'); + + $this->assertEquals($response_data['status'], 1); //1 means accept + + $this->assertEquals($response_data['expiration'], "2020-01-01"); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance + */ + function test_submit_customer_acceptance_as_guest() { + wp_set_current_user(0); + + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/9191919191' ); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertTrue($response->is_error()); + $this->assertEquals($response->get_status(), 401); + + $error_data = $response->as_error(); + $this->assertEquals($error_data->get_error_message(), 'Sorry, you are not allowed to do that.'); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance + */ + function test_submit_nonexisting_customer_acceptance() { + wp_set_current_user(1); + + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919191919191' ); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertTrue($response->is_error()); + $this->assertEquals($response->get_status(), 404); + + $error_data = $response->as_error(); + $this->assertEquals($error_data->get_error_message(), 'Customer acceptance entry not found'); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance + */ + function test_submit_customer_acceptance_with_invalid_status() { + wp_set_current_user(1); + + $customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry(); + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id ); + $request->set_body_params(array( + 'actionType' => 'invalid status', + 'declineReason' => '' + )); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + $this->assertArrayHasKey('messages', $response_data); + $this->assertArrayHasKey('data', $response_data); + + $message = $response_data['messages'][0]; + $this->assertArrayHasKey('code', $message); + $this->assertArrayHasKey('message', $message); + $this->assertEquals('error', $message['code']); + $this->assertEquals('ACCEPTANCE_STATUS_MISSING', $message['message']); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance + */ + function test_submit_customer_acceptance_with_accepted_status() { + wp_set_current_user(1); + + $customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry(); + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id ); + $request->set_body_params(array( + 'actionType' => 'accept', + 'declineReason' => '' + )); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + $this->assertArrayHasKey('messages', $response_data); + $this->assertArrayHasKey('data', $response_data); + + $message = $response_data['messages'][0]; + $this->assertArrayHasKey('code', $message); + $this->assertArrayHasKey('message', $message); + $this->assertEquals('success', $message['code']); + $this->assertEquals('INSTALLATION_ACCEPTED', $message['message']); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance + */ + function test_submit_customer_acceptance_with_declined_status_and_empty_reason() { + wp_set_current_user(1); + + $customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry(); + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id ); + $request->set_body_params(array( + 'actionType' => 'decline', + 'declineReason' => '' + )); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + $this->assertArrayHasKey('messages', $response_data); + $this->assertArrayHasKey('data', $response_data); + + $message = $response_data['messages'][0]; + $this->assertArrayHasKey('code', $message); + $this->assertArrayHasKey('message', $message); + $this->assertEquals('error', $message['code']); + $this->assertEquals('DECLINE_REASON_EMPTY', $message['message']); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance + */ + function test_submit_customer_acceptance_with_decline_status() { + wp_set_current_user(1); + + $customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry(); + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id ); + $request->set_body_params(array( + 'actionType' => 'decline', + 'declineReason' => 'This is very reasonable reason' + )); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + $this->assertArrayHasKey('messages', $response_data); + $this->assertArrayHasKey('data', $response_data); + + $message = $response_data['messages'][0]; + $this->assertArrayHasKey('code', $message); + $this->assertArrayHasKey('message', $message); + $this->assertEquals('success', $message['code']); + $this->assertEquals('INSTALLATION_DECLINED', $message['message']); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::upload_file + */ + function test_upload_customer_acceptance_file_as_guest() { + wp_set_current_user(0); + + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919199191/upload-file' ); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertTrue($response->is_error()); + $this->assertEquals($response->get_status(), 401); + + $error_data = $response->as_error(); + $this->assertEquals($error_data->get_error_message(), 'Sorry, you are not allowed to do that.'); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::upload_file + */ + function test_upload_customer_acceptance_file_to_non_existing_entry() { + wp_set_current_user(1); + + $original_valid_customer_acceptance = __DIR__ . '/../dummy-files/valid-customer-acceptance.odt'; + $this->test_file_valid_customer_acceptance = '/tmp/valid-customer-acceptance.odt'; + copy( $original_valid_customer_acceptance, $this->test_file_valid_customer_acceptance ); + + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919199191/upload-file' ); + + $request->set_file_params( array( + 'file' => array( + 'file' => file_get_contents( $this->test_file_valid_customer_acceptance ), + 'name' => 'valid-customer-acceptance.odt', + 'size' => filesize( $this->test_file_valid_customer_acceptance ), + 'tmp_name' => $this->test_file_valid_customer_acceptance, + ), + ) ); + + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertTrue($response->is_error()); + $this->assertEquals($response->get_status(), 404); + + $error_data = $response->as_error(); + $this->assertEquals($error_data->get_error_message(), 'Customer acceptance entry not found'); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::upload_file + */ + function test_upload_customer_acceptance_file_without_file() { + wp_set_current_user(1); + + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919199191/upload-file' ); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + $this->assertArrayHasKey('messages', $response_data); + $this->assertArrayHasKey('data', $response_data); + + $message = $response_data['messages'][0]; + $this->assertArrayHasKey('code', $message); + $this->assertArrayHasKey('message', $message); + $this->assertEquals('error', $message['code']); + $this->assertEquals('NO_FILES_UPLOADED', $message['message']); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::upload_file + */ + function test_upload_invalid_customer_acceptance_file() { + wp_set_current_user(1); + + $customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry(); + + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id . '/upload-file' ); + $request->set_file_params( array( + 'file' => array( + 'file' => file_get_contents( $this->test_file_invalid_customer_acceptance ), + 'name' => 'invalid-customer-acceptance.txt', + 'size' => filesize( $this->test_file_invalid_customer_acceptance ), + 'tmp_name' => $this->test_file_invalid_customer_acceptance, + ), + ) ); + $request->set_header( 'Content-MD5', md5_file( $this->test_file_invalid_customer_acceptance ) ); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + $this->assertArrayHasKey('messages', $response_data); + $this->assertArrayHasKey('data', $response_data); + + $message = $response_data['messages'][0]; + $this->assertArrayHasKey('code', $message); + $this->assertArrayHasKey('message', $message); + $this->assertEquals('error', $message['code']); + $this->assertEquals('INVALID_FILE_ACCEPTANCE', $message['message']); + } + + /** + * @covers Wiass_REST_Delivery_Process_API::upload_file + */ + function test_upload_valid_customer_acceptance_file() { + wp_set_current_user(1); + + $customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry(); + + $request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id . '/upload-file' ); + $request->set_file_params( array( + 'file' => array( + 'file' => file_get_contents( $this->test_file_valid_customer_acceptance ), + 'name' => 'valid-customer-acceptance.odt', + 'size' => filesize( $this->test_file_valid_customer_acceptance ), + 'tmp_name' => $this->test_file_valid_customer_acceptance, + ), + ) ); + $request->set_header( 'Content-MD5', md5_file( $this->test_file_valid_customer_acceptance ) ); + $response = $this->server->dispatch( $request ); + + $this->assertNotNull($response); + $this->assertInstanceOf('WP_REST_Response',$response); + $this->assertFalse($response->is_error()); + $this->assertEquals($response->get_status(), 200); + + $response_data = $response->get_data(); + $this->assertArrayHasKey('messages', $response_data); + $this->assertArrayHasKey('data', $response_data); + + $message = $response_data['messages'][0]; + $this->assertArrayHasKey('code', $message); + $this->assertArrayHasKey('message', $message); + $this->assertEquals('success', $message['code']); + $this->assertEquals('FILE_UPLOADED', $message['message']); + } + + public function tearDown() { + parent::tearDown(); + if ( file_exists( $this->test_file_valid_customer_acceptance ) ) { + unlink( $this->test_file_valid_customer_acceptance ); + } + if ( file_exists( $this->test_file_invalid_customer_acceptance ) ) { + unlink( $this->test_file_invalid_customer_acceptance ); + } + + $this->remove_added_uploads(); + } + + + + //=================================================================================== + /** + * Helper function : creates customer acceptance entry + */ + private function create_pending_customer_acceptance_entry(){ + $customer_acceptance_form_id = 1; + + $customer_id_field_id = 2; + $actual_date_field_id = 6; + $acceptance_status_field_id = 8; + $expiration_date_field_id = 9; + $decline_reason_field_id = 10; + $files_uploaded_field_id = 12; + + $input_values['input_' . $acceptance_status_field_id] = 'accept'; + $input_values['input_' . $expiration_date_field_id] = "2020-01-01"; + //$input_values['input_' . $files_uploaded_field_id] = json_encode(['http://path/to/file1.docx']); + + GFAPI::submit_form($customer_acceptance_form_id, $input_values); + + //this part is needed since form submit does not store files for some reason, probably files should be sent some other way + $entry = GFAPI::get_entries($customer_acceptance_form_id)[0]; + $entry[$files_uploaded_field_id] = json_encode(['http://localhost/wp/index.php?gf-download=2018%2F08%2Ffile1.docx&form-id=1&field-id=12&hash=1be6c30f0eeff93563b352d15fe459d5ded12ee06c2c8f36fed66b42dedf2534']); + $entry['workflow_step'] = 1; + $entry['workflow_step_status_1'] = 'pending'; + $entry['workflow_step_status_2'] = false; + $entry['workflow_timestamp'] = false; + $update = GFAPI::update_entry($entry); + + return $entry['id']; + } + + } diff --git a/backend/app/plugins/wiaas/tests/wiaas-unit-test-case.php b/backend/app/plugins/wiaas/tests/wiaas-unit-test-case.php index 4bf3518..53971cb 100644 --- a/backend/app/plugins/wiaas/tests/wiaas-unit-test-case.php +++ b/backend/app/plugins/wiaas/tests/wiaas-unit-test-case.php @@ -14,7 +14,9 @@ class Wiaas_Unit_Test_Case extends WP_UnitTestCase { wiaas_db_update_setup_gravity(); - wiaas_db_update_enable_orders_access_management(); + wiaas_db_update_enable_orders_access_management(); + + define('WP_TEST_IN_PROGRESS',true); } function tearDown() { diff --git a/backend/composer.lock b/backend/composer.lock index b59d0b9..527c55b 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -1,7 +1,7 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], "content-hash": "302f569929ecdaf4d349b0bf764de74c", diff --git a/frontend/src/actions/login/authActions.js b/frontend/src/actions/login/authActions.js index b1b9881..55e2b4d 100644 --- a/frontend/src/actions/login/authActions.js +++ b/frontend/src/actions/login/authActions.js @@ -118,6 +118,7 @@ export const validateCredentials = (username, password) => { // if(decodedAceessToken.data.wiaas_user_type === 'customer'){ localStorage.setItem('accessToken', response.data.token); + localStorage.setItem('username', username); const serverTime = decodedAceessToken.nbf || 1; // refreshToken = response.data.refreshToken; startRefreshTimer(dispatch, serverTime); diff --git a/frontend/src/actions/orders/customerAcceptanceActions.js b/frontend/src/actions/orders/customerAcceptanceActions.js index 59f5cf7..642a22d 100644 --- a/frontend/src/actions/orders/customerAcceptanceActions.js +++ b/frontend/src/actions/orders/customerAcceptanceActions.js @@ -23,15 +23,12 @@ const recieveCustomerAcceptance = (json) => ({ customerAcceptance: json }); -export const fetchCustomerAcceptance = (idOrder) => { +export const fetchCustomerAcceptance = (idEntry) => { return dispatch => { dispatch(requestCustomerAcceptance()); return htmlClient.fetch({ - url: `${API_SERVER}/orders/api/getCustomerAcceptance`, - method: 'post', - data: { - idOrder - } + url: `${API_SERVER}/wp-json/wiaas/customer-acceptance/${idEntry}`, + method: 'get' }) .then(response => { if (response.data) { @@ -48,18 +45,15 @@ const uploadAcceptanceAction = () => ({ type: UPLOAD_CUSTOMER_ACCEPTANCE }); -export const uploadAcceptance = (idOrder, file) => { +export const uploadAcceptance = (idEntry, file) => { return dispatch => { dispatch(uploadAcceptanceAction()); return htmlClient.uploadFile(file, { - url: `${API_SERVER}/orders/api/uploadAcceptanceDocument`, - data: { - idOrder - } + url: `${API_SERVER}/wp-json/wiaas/customer-acceptance/${idEntry}/upload-file` }).then(response => { - if (typeof response.data !== 'undefined' && 'messages' in response.data) { + if (typeof response.data !== 'undefined') { dispatch(updateMessages(response.data.messages, orderMessages)); - dispatch(fetchCustomerAcceptance(idOrder)); + dispatch(fetchCustomerAcceptance(idEntry)); } }).catch(error => { htmlClient.onError(error, dispatch); @@ -77,14 +71,13 @@ const sendCustomerAcceptance = () => ({ type: SEND_CUSTOMER_ACCEPTANCE }); -export const acceptDeclineInstallation = (idOrder, actionType, declineReason) => { +export const acceptDeclineInstallation = (idEntry, actionType, declineReason) => { return dispatch => { dispatch(sendCustomerAcceptance()); return htmlClient.fetch({ - url: `${API_SERVER}/orders/api/acceptDeclineInstallation`, + url: `${API_SERVER}/wp-json/wiaas/customer-acceptance/${idEntry}`, method: 'post', data: { - idOrder, actionType, declineReason } @@ -92,7 +85,7 @@ export const acceptDeclineInstallation = (idOrder, actionType, declineReason) => .then(response => { if (response.data) { dispatch(updateMessages(response.data.messages, orderMessages)); - dispatch(fetchCustomerAcceptance(idOrder)); + dispatch(fetchCustomerAcceptance(idEntry)); } }) .catch(error => { diff --git a/frontend/src/actions/orders/processActions.js b/frontend/src/actions/orders/processActions.js index 9ea9ce4..87bef48 100644 --- a/frontend/src/actions/orders/processActions.js +++ b/frontend/src/actions/orders/processActions.js @@ -24,7 +24,9 @@ import { SET_SCHEDULING_DISABLED_FLAG } from '../../constants/ordersConstants'; import HtmlClient from '../../helpers/HtmlClient'; -import {updateMessages} from '../notification/notificationActions'; +import { updateMessages } from '../notification/notificationActions'; +import { fromWCOrder } from '../../helpers/OrderHelper'; +import moment from 'moment'; const htmlClient = new HtmlClient(); @@ -42,15 +44,12 @@ export const fetchOrderInfo = (idOrder) => { return dispatch => { dispatch(requestOrderInfo()); return htmlClient.fetch({ - url: `${API_SERVER}/orders/api/getOrderInfo`, - method: 'post', - data: { - idOrder - } - }) + url: `${API_SERVER}/wp-json/wc/v2/orders/${idOrder}`, + method: 'get' + }) .then(response => { if (response.data) { - dispatch(recieveOrderInfo(response.data)); + dispatch(recieveOrderInfo(fromWCOrder(response.data))); } }) .catch(error => { @@ -63,22 +62,28 @@ const sendComment = () => ({ type: SEND_ORDER_COMMENT }) -export const addComment = (idOrder, comment) => { +export const addComment = (idOrder, newComment) => { return dispatch => { dispatch(sendComment()); + return htmlClient.fetch({ - url: `${API_SERVER}/orders/api/addOrderComment`, - method: 'post', - data: { - idOrder, - comment - } - }) + url: `${API_SERVER}/wp-json/wc/v2/orders/${idOrder}/notes`, + method: 'post', + data: { + note : newComment || 'Test comment', + customer_note: true, + } + }) .then(response => { + if (response.data) { + dispatch(fetchOrderInfo(idOrder)); + } + /* if (response.data && response.data.messages) { dispatch(updateMessages(response.data.messages, orderMessages)); dispatch(fetchOrderInfo(idOrder)); } + */ }) .catch(error => { htmlClient.onError(error, dispatch); diff --git a/frontend/src/constants/ordersConstants.js b/frontend/src/constants/ordersConstants.js index 6eaaeee..b2d9b2e 100644 --- a/frontend/src/constants/ordersConstants.js +++ b/frontend/src/constants/ordersConstants.js @@ -50,13 +50,13 @@ export const orderMessages = { SYSTEM_ALLOWED_LANGUAGES_EMPTY: 'There are no languages added in the system.', ALLOWED_LANGUAGE: 'Allowed languages are:', ALLOWED_LANGUAGE_ERROR: 'There was an error while trying to detect the language:', - SERVER_ERROR: 'There seems to be a problem and the comment was not added!', + ERROR_ADDING_COMMENT: 'There seems to be a problem and the comment was not added!', ORDER_COMMENT_ADDED: 'Order comment updated!', FILE_UPLOADED : 'File has been uploaded and needs to be validated!', NOT_UPLOADED : 'There seems to be a problem and the file was not uploaded!', RE_UPLOAD_MAIL : 'Notify mail has been sent!', ACCEPTANCE_NOT_UPDATED : 'Acceptance status not updated!', - ACCEPTANCE_NOT_UPLOADED: 'You need to uploade the acceptance document before you can agree with the installation!', + ACCEPTANCE_NOT_UPLOADED: 'You need to upload the acceptance document before you can agree with the installation!', DECLINE_REASON_EMPTY : 'Please describe what is not to your satisfaction.', INSTALLATION_DECLINED : 'The implementation is not satisfactory.', ERROR_MAIL_SENT : 'Notify mail was not sent!', @@ -81,7 +81,13 @@ export const orderMessages = { EMPTY_VALUE: 'Field required: ', INSTALLATION_ACCEPTED: 'The implementation has been accepted!', ID_ORDER_NOT_SET: 'The id of the order is not set', - SUPPORT_MAIL_SENT: 'Support mail sent!' + SUPPORT_MAIL_SENT: 'Support mail sent!', + + NO_FILES_UPLOADED: 'You need to upload the acceptance document', + INTERNAL_SERVER_ERROR: 'Error occured. Please try again', + ACCEPTANCE_STATUS_MISSING: 'Acceptance action not selected', + ACCEPTANCE_STATUS_UPDATED: 'Acceptance status updated' + }; export const orderTexts = { @@ -161,7 +167,11 @@ export const orderTexts = { INSTALLATION_DATE: 'Installation date', INSTALLATION_NOT_REQUIRED:'Installation is not required for this package', PRELIMINARY_INSTALLATION_DATE_LABEL: 'Preliminary installation date', - PROJECT: 'Project' + PROJECT: 'Project', + BILLING_FIRST_NAME: 'Billing first name', + BILLING_LAST_NAME: 'Billing last name', + BILLING_MAIL: 'Invoice mail', + BILLING_ADDRESS: 'Billing address' }, buttons: { ACCEPT_INSTALLATION: 'I agree', diff --git a/frontend/src/containers/orders/ProcessContainer.jsx b/frontend/src/containers/orders/ProcessContainer.jsx index fe34fc6..4c04de0 100644 --- a/frontend/src/containers/orders/ProcessContainer.jsx +++ b/frontend/src/containers/orders/ProcessContainer.jsx @@ -44,7 +44,7 @@ class ProcessContainer extends Component { componentDidMount() { this.props.dispatch(fetchOrderInfo(this.props.idOrder)); - this.props.dispatch(getAllDataForInstallation(this.props.idOrder, usedForDirective, stepsNameForInstallation, fileType)); + //this.props.dispatch(getAllDataForInstallation(this.props.idOrder, usedForDirective, stepsNameForInstallation, fileType)); const orderPackagePairs = []; const isSchedulingDisabled = {}; isSchedulingDisabled[this.props.idOrder] = true; @@ -52,7 +52,7 @@ class ProcessContainer extends Component { if(this.props.orderInfo) { this.props.orderInfo.packages.forEach(orderPackage => { - orderPackagePairs.push(orderPackage.idOrder + '-' + orderPackage.idPackage); + orderPackagePairs.push(this.props.orderInfo.id + '-' + orderPackage.id); }); } this.setState({ @@ -71,11 +71,11 @@ class ProcessContainer extends Component { if(installCompanies && isComponentDisabled && earliestInstallDate) { if(nextProps.orderInfo) { + const idOrder = nextProps.orderInfo.id; nextProps.orderInfo.packages.forEach(orderPackage => { - const idOrder = orderPackage && orderPackage.idOrder; - const idOrderPackagePair = orderPackage ? idOrder + '-' + orderPackage.idPackage : ''; + const idOrderPackagePair = orderPackage ? idOrder + '-' + orderPackage.id : ''; orderPackage.idOrderPackagePair = idOrderPackagePair; - areComponentsDisabled[idOrder] = this.checkIfComponentIsDisabled(orderPackage.idOrder, isComponentDisabled, earliestInstallDate); + areComponentsDisabled[idOrder] = this.checkIfComponentIsDisabled(idOrder, isComponentDisabled, earliestInstallDate); const availableCompanies = {}; const selectedCompanies = {}; @@ -101,7 +101,7 @@ class ProcessContainer extends Component { }); const isSchedulingDisabled = Object.assign({}, this.state.isSchedulingDisabled); - isSchedulingDisabled[nextProps.orderInfo.info.id] = allPackagesScheduleInstallDisabled.every(isDisabled => {return isDisabled === true;}); + isSchedulingDisabled[nextProps.orderInfo.id] = allPackagesScheduleInstallDisabled.every(isDisabled => {return isDisabled === true;}); this.setState({ isSchedulingDisabled, areComponentsDisabled, @@ -126,16 +126,16 @@ class ProcessContainer extends Component { return true; } - calculatetTotalPrice(packages) { - let fixedPrice = priceHelper.sumPrices(packages.map(pkg => { return pkg.units * pkg.packageFixedPrice})); - let recurrentPrice = priceHelper.sumPrices(packages.map(pkg => { return pkg.units * pkg.packageRecuringPrice})); - let servicesPrice = priceHelper.sumPrices(packages.map(pkg => { return pkg.units * pkg.packageServicePrice})); + calculatetTotalPrice(packages, currency) { + let fixedPrice = priceHelper.sumPrices(packages.map(pkg => { return pkg.quantity * pkg.price})); + let recurrentPrice = priceHelper.sumPrices(packages.map(pkg => { return pkg.quantity * pkg.recurringPrice})); + let servicesPrice = priceHelper.sumPrices(packages.map(pkg => { return pkg.quantity * pkg.servicePrice})); return { fixedPrice, recurrentPrice: priceHelper.sumPrices([recurrentPrice, servicesPrice]), periodUnit: packages[0].periodUnit, - currency: packages[0].packageCurrency.currency + currency: currency } } @@ -158,15 +158,10 @@ class ProcessContainer extends Component { if(this.state.packageNameFilter === 'all') { return true; }else{ - return orderPackage.packageName === this.state.packageNameFilter; + return orderPackage.name === this.state.packageNameFilter; } } - getProcess(process){ - const processKeys = Object.keys(process) || []; - return processKeys.length > 0 ? process[processKeys[0]] : {}; - } - getButtonClass() { if(this.props.orderInfo) { return this.state.isSchedulingDisabled[this.props.orderInfo.id] ? 'schedule-inactive' : 'schedule-active'; @@ -187,18 +182,18 @@ class ProcessContainer extends Component { } { - (orderInfo && orderInfo.info && !isLoading) && + (orderInfo && !isLoading) &&
- + { this.state.activeView !== 'info' && @@ -211,7 +206,7 @@ class ProcessContainer extends Component { + orderProcess={orderInfo.process}/> } { this.state.activeView === 'packages' && @@ -221,9 +216,10 @@ class ProcessContainer extends Component { > { orderInfo.packages.filter(this.filterPackages).map(orderPackage => - ) } @@ -231,18 +227,18 @@ class ProcessContainer extends Component { } { this.state.activeView === 'comments' && - + } { this.state.activeView === 'documents' && - + }
} { - (orderInfo && !orderInfo.info && !isLoading) && + (!orderInfo && !isLoading) &&
{orderTexts.labels.NOT_AVAILABLE}!
diff --git a/frontend/src/containers/orders/components/OrderComments.jsx b/frontend/src/containers/orders/components/OrderComments.jsx index 85fc4c3..0c43852 100644 --- a/frontend/src/containers/orders/components/OrderComments.jsx +++ b/frontend/src/containers/orders/components/OrderComments.jsx @@ -18,7 +18,7 @@ class OrderComments extends Component { } addNewComment(){ - this.props.dispatch(addComment(this.props.orderInfo.id, this.state.newComment)); + this.props.dispatch(addComment(this.props.orderInfo.id, this.state.newComment, this.props.orderComments)); } onEditorChange(newComment){ @@ -26,11 +26,11 @@ class OrderComments extends Component { } getOffset(isOwner){ - return isOwner ? 6 : 0; + return (isOwner) ? 6 : 0; } getClassByOwner(isOwner){ - return isOwner ? 'mine' : ''; + return (isOwner) ? 'mine' : ''; } render() { @@ -48,7 +48,7 @@ class OrderComments extends Component {
-
{orderComment.username} - {orderComment.addDate}
+
{orderComment.username} - {orderComment.dateCreated}
diff --git a/frontend/src/containers/orders/components/OrderDocuments.jsx b/frontend/src/containers/orders/components/OrderDocuments.jsx index 555d86e..1b42f47 100644 --- a/frontend/src/containers/orders/components/OrderDocuments.jsx +++ b/frontend/src/containers/orders/components/OrderDocuments.jsx @@ -10,10 +10,10 @@ class OrderDocuments extends Component { return (
{ - orderInfo.packages.map(orderPackage => ) + orderInfo.packages.map(orderPackage => ) } { - orderInfo.orderDocuments && + orderInfo.orderDocuments && }
); diff --git a/frontend/src/containers/orders/components/OrderDocumentsGroup.jsx b/frontend/src/containers/orders/components/OrderDocumentsGroup.jsx index 5f15380..cd11fb0 100644 --- a/frontend/src/containers/orders/components/OrderDocumentsGroup.jsx +++ b/frontend/src/containers/orders/components/OrderDocumentsGroup.jsx @@ -57,6 +57,7 @@ class OrderDocumentsGroup extends Component { return (
{ + documentsGroup.documents && documentsGroup.documents.length > 0 && { diff --git a/frontend/src/containers/orders/components/OrderInfo.jsx b/frontend/src/containers/orders/components/OrderInfo.jsx index 89bd912..5ba0603 100644 --- a/frontend/src/containers/orders/components/OrderInfo.jsx +++ b/frontend/src/containers/orders/components/OrderInfo.jsx @@ -27,7 +27,7 @@ class OrderInfo extends Component { setInstallationData(props) { const acceptedDate = {}; const proposedDate = {}; - const idOrder = props.orderDetails.info.id; + const idOrder = props.orderDetails.id; const {isInstallationInPackage} = props.installationData; const {confirmationDates, areAllShippingDatesConfirmed} = props; const isPreliminaryInstallationDate = areAllShippingDatesConfirmed && idOrder in areAllShippingDatesConfirmed ? !areAllShippingDatesConfirmed[idOrder] : true; @@ -53,18 +53,28 @@ class OrderInfo extends Component { const {acceptedDate, proposedDate, isPreliminaryInstallationDate, isInstallationInOrder} = this.state; const orderPackages = installationData.packages; const isInstallationInPackage = installationData.isInstallationInPackage; - const orderInfo = this.props.orderInfo.info; + const orderInfo = this.props.orderInfo; return (
{orderTexts.labels.ORDER_DATE}:
- {orderInfo.orderDate} + {orderInfo.dateCreated}
{orderTexts.labels.SOLD_BY}:
- {orderInfo.commercialLead} + {orderInfo.commercialLead.name} + +
{orderTexts.labels.BILLING_FIRST_NAME}:
+ {orderInfo.billing.firstName || '-'} +
{orderTexts.labels.BILLING_LAST_NAME}:
+ {orderInfo.billing.lastName || '-'} +
{orderTexts.labels.BILLING_MAIL}:
+ {orderInfo.billing.email || '-'} +
{orderTexts.labels.BILLING_ADDRESS}:
+ {orderInfo.billing.address || '-'} +
{orderTexts.labels.REFERENCE}:
diff --git a/frontend/src/containers/orders/components/PackagesNav.jsx b/frontend/src/containers/orders/components/PackagesNav.jsx index 51207fe..a2eb098 100644 --- a/frontend/src/containers/orders/components/PackagesNav.jsx +++ b/frontend/src/containers/orders/components/PackagesNav.jsx @@ -21,9 +21,9 @@ class PackageNav extends Component {
{onPackageFilter('all')}}>{orderTexts.buttons.ALL}
{ packages.length > 0 && - packages.map((orderPackage) =>
{onPackageFilter(orderPackage.packageName)}} - className={this.getClass(orderPackage.packageName)}>{orderPackage.packageName}
) + packages.map((orderPackage) =>
{onPackageFilter(orderPackage.name)}} + className={this.getClass(orderPackage.name)}>{orderPackage.name}
) } diff --git a/frontend/src/containers/orders/components/packages/PackageInfo.jsx b/frontend/src/containers/orders/components/packages/PackageInfo.jsx index 27040ad..66d086e 100644 --- a/frontend/src/containers/orders/components/packages/PackageInfo.jsx +++ b/frontend/src/containers/orders/components/packages/PackageInfo.jsx @@ -29,8 +29,8 @@ class PackageInfo extends Component { } render() { - const {orderPackage, onViewChange} = this.props; - const shouldShowPriceInfo = orderPackage.packageRecuringPrice > 0 || orderPackage.packageServicePrice > 0; + const {orderPackage, currency, onViewChange} = this.props; + const shouldShowPriceInfo = orderPackage.recurringPrice > 0 || orderPackage.servicePrice > 0; return ( @@ -41,7 +41,7 @@ class PackageInfo extends Component { {orderTexts.labels.PACKAGE_PRICE}: {' '} { shouldShowPriceInfo && } @@ -49,43 +49,43 @@ class PackageInfo extends Component {
{orderTexts.labels.TOTAL_DELVIERY_PRICE}: {' '} - {(orderPackage.units * orderPackage.packageFixedPrice).toLocaleString() + ' ' + orderPackage.packageCurrency.currency} + {(orderPackage.quantity * orderPackage.price).toLocaleString() + ' ' + currency}
{ shouldShowPriceInfo &&
{orderTexts.labels.TOTAL_RECURRENT_PRICE}:{' '} - {(orderPackage.units * (orderPackage.packageRecuringPrice + orderPackage.packageServicePrice)).toLocaleString()} {orderPackage.packageCurrency.currency} + {(orderPackage.quantity * (orderPackage.recurringPrice + orderPackage.servicePrice)).toLocaleString()} {currency}
} { shouldShowPriceInfo && {orderPackage.paymentType}
- { orderPackage.packageRecuringPrice > 0 && + { orderPackage.recurringPrice > 0 &&
{orderTexts.labels.RECURRENT_PRICE}: - {(orderPackage.units * orderPackage.packageRecuringPrice).toLocaleString()} {orderPackage.packageCurrency.currency} / {orderPackage.periodUnit} + {(orderPackage.quantity * orderPackage.recurringPrice).toLocaleString()} {currency} / {orderPackage.periodUnit} { orderPackage.packagePayPeriod > 0 && - for {orderPackage.packagePayPeriod} {orderPackage.periodUnit} + for {orderPackage.payPeriod} {orderPackage.periodUnit} }
} - { orderPackage.packageServicePrice > 0 && + { orderPackage.servicePrice > 0 &&
{orderTexts.labels.SERVICES_PRICE}: - {(orderPackage.units * orderPackage.packageServicePrice).toLocaleString()} {orderPackage.packageCurrency.currency} / {orderPackage.periodUnit} + {(orderPackage.quantity * orderPackage.servicePrice).toLocaleString()} {currency} / {orderPackage.periodUnit} { orderPackage.servicesContractPeriod > 0 && @@ -101,7 +101,7 @@ class PackageInfo extends Component { } { - orderPackage.options.length > 0 && + orderPackage.options && orderPackage.options.length > 0 &&
{orderTexts.labels.OPTIONS}:
{ @@ -112,7 +112,7 @@ class PackageInfo extends Component { } { - orderPackage.additionalPackages.length > 0 && + orderPackage.additionalPackages && orderPackage.additionalPackages.length > 0 &&
{orderTexts.labels.ADDITIONAL_PACKAGES}:
{ diff --git a/frontend/src/containers/orders/components/packages/PackageName.jsx b/frontend/src/containers/orders/components/packages/PackageName.jsx index 79f8d28..3a665e0 100644 --- a/frontend/src/containers/orders/components/packages/PackageName.jsx +++ b/frontend/src/containers/orders/components/packages/PackageName.jsx @@ -7,7 +7,7 @@ class PackageName extends Component { return (
- {orderPackage.units + ' x ' + orderPackage.packageName} + {orderPackage.quantity + ' x ' + orderPackage.name}
); } diff --git a/frontend/src/containers/orders/components/packages/ProcessPackage.jsx b/frontend/src/containers/orders/components/packages/ProcessPackage.jsx index f1c9743..d08e742 100644 --- a/frontend/src/containers/orders/components/packages/ProcessPackage.jsx +++ b/frontend/src/containers/orders/components/packages/ProcessPackage.jsx @@ -6,13 +6,13 @@ import PackageName from './PackageName.jsx'; class ProcessPackage extends Component { render() { - const {orderPackage, idCommercialLead} = this.props; + const {orderPackage, currency, idCommercialLead} = this.props; return ( - + diff --git a/frontend/src/containers/orders/components/process/CustomerAcceptance.jsx b/frontend/src/containers/orders/components/process/CustomerAcceptance.jsx index 50feaed..4d12479 100644 --- a/frontend/src/containers/orders/components/process/CustomerAcceptance.jsx +++ b/frontend/src/containers/orders/components/process/CustomerAcceptance.jsx @@ -5,7 +5,6 @@ import {Row, Col, Button} from 'reactstrap'; import {fetchCustomerAcceptance, uploadAcceptance, acceptDeclineInstallation, badFile} from '../../../../actions/orders/customerAcceptanceActions'; import {setDialogContent, setDialogOpenFlag} from '../../../../actions/dialog/dialogActions'; import AcceptanceDeclineReason from './AcceptanceDeclineReason.jsx'; -import {API_SERVER} from '../../../../config'; import FileDownloader from '../../../../helpers/FileDownloader'; import {orderTexts} from '../../../../constants/ordersConstants'; import '../../style/CustomerAcceptance.css'; @@ -26,15 +25,16 @@ class CustomerAcceptance extends Component { } downloadDocument(document){ - const fileUrl = `${API_SERVER}/utils/api/downloadFile?idDocument=${document.idDocument}&fileName=${document.documentName}.${document.extension}` - const fileName = document.documentName + '.' + document.extension; + //const fileUrl = `${API_SERVER}/utils/api/downloadFile?idDocument=${document.idDocument}&fileName=${document.documentName}.${document.extension}` + const fileUrl = document.url; + const fileName = document.name + '.' + document.extension; fileHandler.download(fileUrl, fileName); } - uploadFile(idOrder, acceptedFiles, rejectedFiles) { + uploadFile(idEntry, acceptedFiles, rejectedFiles) { if(acceptedFiles && acceptedFiles.length){ const file = acceptedFiles[0]; - this.props.dispatch(uploadAcceptance(idOrder, file)); + this.props.dispatch(uploadAcceptance(idEntry, file)); } if(rejectedFiles && rejectedFiles.length) { @@ -59,9 +59,9 @@ class CustomerAcceptance extends Component { } acceptDeclineInstallation() { - const {idOrder} = this.props.step; + const {idProcess} = this.props.step; const {actionType, reason} = this.state; - this.props.dispatch(acceptDeclineInstallation(idOrder, actionType, reason)); + this.props.dispatch(acceptDeclineInstallation(idProcess, actionType, reason)); this.setState({reason: ''}); } @@ -72,7 +72,7 @@ class CustomerAcceptance extends Component { '-1' : orderTexts.labels.DECLINED } - return messages[customerAcceptance.customerAccepted]; + return messages[customerAcceptance.status]; } onEditorChange(reason) { @@ -107,8 +107,8 @@ class CustomerAcceptance extends Component { } componentDidMount(){ - const {idOrder} = this.props.step; - this.props.dispatch(fetchCustomerAcceptance(idOrder)); + const {idProcess} = this.props.step; + this.props.dispatch(fetchCustomerAcceptance(idProcess)); } render() { @@ -121,14 +121,14 @@ class CustomerAcceptance extends Component { customerAcceptance && - {this.getAcceptanceMessage(customerAcceptance)}
+ {this.getAcceptanceMessage(customerAcceptance)}
} { - (customerAcceptance && customerAcceptance.customerAccepted === -1) && + (customerAcceptance && customerAcceptance.status === -1) && - {orderTexts.labels.REASON}: {customerAcceptance.customerDeclineReason} + {orderTexts.labels.REASON}: {customerAcceptance.decline_reason} } @@ -137,19 +137,18 @@ class CustomerAcceptance extends Component { multiple={false} accept=".pdf,.docx,.doc,.xlsx,.xls,.odt,.ods,.jpg,.png,.jpeg" activeClassName="upload-file-accept" - onDrop={(acceptedFiles, rejectedFiles)=>{this.uploadFile(step.idOrder, acceptedFiles, rejectedFiles)}}> + onDrop={(acceptedFiles, rejectedFiles)=>{this.uploadFile(step.idProcess, acceptedFiles, rejectedFiles)}}>
{orderTexts.labels.UPLOAD_ACCEPTANCE_LABEL}
{ - (customerAcceptance && customerAcceptance.acceptanceDocuments && customerAcceptance.acceptanceDocuments.length > 0) && + (customerAcceptance && customerAcceptance.documents && customerAcceptance.documents.length > 0) &&
{ - customerAcceptance.acceptanceDocuments.map(document =>
- {this.downloadDocument(document)}}> - {document.documentName} ({document.extension}) + customerAcceptance.documents.map((document, index) =>
+ + {document.name} ({document.extension}) {document.validation}
@@ -159,7 +158,7 @@ class CustomerAcceptance extends Component {
} { - (customerAcceptance && !customerAcceptance.acceptanceDocuments) && + (customerAcceptance && (!customerAcceptance.documents || customerAcceptance.documents.length === 0) ) &&
{orderTexts.labels.NO_DOCUMENTS_UPLOADED}
diff --git a/frontend/src/containers/orders/components/process/OrderProcess.jsx b/frontend/src/containers/orders/components/process/OrderProcess.jsx index b6087fb..3424e32 100644 --- a/frontend/src/containers/orders/components/process/OrderProcess.jsx +++ b/frontend/src/containers/orders/components/process/OrderProcess.jsx @@ -7,7 +7,7 @@ const completedOrdersStatuses = ['production', 'end-of-life']; class OrderProcess extends Component { isStepVisible(step) { - return (step.status === 'in-progress' || step.status === 'done') && step.isVisibleForCustomer === 1; + return (step.status === 'pending' || step.status === 'complete') && step.isVisibleForCustomer === 1; } render() { @@ -41,7 +41,7 @@ class OrderProcess extends Component { { - visibleSteps.map((step, index) => ) + visibleSteps.reverse().map((step, index) => ) } diff --git a/frontend/src/containers/orders/components/process/ProcessStep.jsx b/frontend/src/containers/orders/components/process/ProcessStep.jsx index a369c74..2f68ee2 100644 --- a/frontend/src/containers/orders/components/process/ProcessStep.jsx +++ b/frontend/src/containers/orders/components/process/ProcessStep.jsx @@ -11,7 +11,7 @@ const stepActions = { class OrderStep extends Component { isActiveStep(status) { - return status === 'in-progress' ; + return status === 'pending' ; } getStepTitle(step, stepNumber) { diff --git a/frontend/src/containers/orders/components/process/ValidateQuestionnaire.jsx b/frontend/src/containers/orders/components/process/ValidateQuestionnaire.jsx index 9e27ab5..08cb7b5 100644 --- a/frontend/src/containers/orders/components/process/ValidateQuestionnaire.jsx +++ b/frontend/src/containers/orders/components/process/ValidateQuestionnaire.jsx @@ -8,8 +8,8 @@ class ValidateQuestionnaire extends Component { componentDidMount(){ const {idOrder, idProcessStep} = this.props.step; - this.props.dispatch(fetchCustomerDocuments(idOrder, 'orderQuestionaire')); - this.props.dispatch(fetchValidationComments(idOrder, idProcessStep, 'invalidQuestionnaireComment')); + //this.props.dispatch(fetchCustomerDocuments(idOrder, 'orderQuestionaire')); + //this.props.dispatch(fetchValidationComments(idOrder, idProcessStep, 'invalidQuestionnaireComment')); } findById(orderPackage, idOrderPackagePair){ diff --git a/frontend/src/containers/orders/style/ProcessContainer.scss b/frontend/src/containers/orders/style/ProcessContainer.scss index f3e72cf..3e4d82e 100644 --- a/frontend/src/containers/orders/style/ProcessContainer.scss +++ b/frontend/src/containers/orders/style/ProcessContainer.scss @@ -26,6 +26,7 @@ $link-line-height: 1.5rem; .completed { border-left: $border-width $production-status-color solid; + background: $production-status-color; } .end-of-life { @@ -131,7 +132,7 @@ $link-line-height: 1.5rem; background: $canceled-status-color; } -.production { +.completed { background: $production-status-color; } @@ -139,11 +140,15 @@ $link-line-height: 1.5rem; background: $open-status-color; } -.done { +.complete { background: $done-status-color; } -.in-progress { +.processing { + background: $in-progress-status-color; +} + +.pending { background: $in-progress-status-color; } diff --git a/frontend/src/helpers/HtmlClient.js b/frontend/src/helpers/HtmlClient.js index 4bf4dab..0f92822 100644 --- a/frontend/src/helpers/HtmlClient.js +++ b/frontend/src/helpers/HtmlClient.js @@ -45,11 +45,14 @@ class HtmlClient { uploadFile(file, configParams = null) { let formData = new FormData(); formData.append('file', file, file.name); + /* if(configParams) { + Object.keys(configParams.data).forEach((paramKey) => { formData.append(paramKey, configParams.data[paramKey]); }); - } + + }*/ configParams.data = formData; const params = Object.assign({}, uploadParams(), configParams); diff --git a/frontend/src/helpers/OrderHelper.js b/frontend/src/helpers/OrderHelper.js index 9eafd55..e9f50ff 100644 --- a/frontend/src/helpers/OrderHelper.js +++ b/frontend/src/helpers/OrderHelper.js @@ -1,4 +1,5 @@ import moment from 'moment'; +import {fromWiaasProcessStep} from './ProcessHelper'; function formatDate(date) { return date ? moment(date).format("Do MMM, YYYY") : undefined; @@ -9,6 +10,10 @@ function formatAddress(addressObject) { } export const fromWCOrder = (WCOrder) => { + let processInfo = Object.assign({},WCOrder['delivery-process']); + if (WCOrder['delivery-process']){ + processInfo.steps = WCOrder['delivery-process'].steps.map(step=>fromWiaasProcessStep(step)); + } return { id: WCOrder.id, number: WCOrder.number, @@ -22,6 +27,12 @@ export const fromWCOrder = (WCOrder) => { recurringPrice: 0, status: WCOrder.status, currency: WCOrder.currency, + billing:{ + firstName: WCOrder.billing.first_name, + lastName: WCOrder.billing.last_name, + email: WCOrder.billing.email, + address: formatAddress(WCOrder.billing) + }, packages: WCOrder['line_items'].map(packageLine => { return { id: packageLine['product_id'], @@ -40,6 +51,14 @@ export const fromWCOrder = (WCOrder) => { dateCompleted: formatDate(packageLine['date_completed']), }; }), + process: processInfo, + comments: WCOrder.comments ? WCOrder.comments.map(comment => ({ + id: comment.id, + comment: comment.content, + username: comment.username, + dateCreated: formatDate(comment.date), + isOwner: comment['is_owner'] + })) : [], deliveryAddress: formatAddress(WCOrder.shipping), customer: WCOrder.customer, commercialLead: WCOrder['commercial_lead'] diff --git a/frontend/src/helpers/ProcessHelper.js b/frontend/src/helpers/ProcessHelper.js new file mode 100644 index 0000000..74d1c8e --- /dev/null +++ b/frontend/src/helpers/ProcessHelper.js @@ -0,0 +1,19 @@ +import moment from "moment"; + +export const fromWiaasProcessStep = (step) => { + return { + actionCode: step.action_code, + actualDate: step.actual_date, + comments: step.comments, + fullDesc: step.full_desc, + idOrder: step.order_id, + idProcess: step.step_form_entry_id, //not sure about this + idProcessStep: step.step_id, //not sure about this + isNewCommentVisible: 1, //TODO : get this from backend + isVisibleForCustomer: 1, //TODO : get this from backend + now: moment().format("Do MMM YY"), + shortDesc: step.short_desc, + status: step.status, + stepType: step.step_type, + } +}; \ No newline at end of file