2
\$\begingroup\$

I am writing a WordPress plugin that allows shipping calculation on the product page. Originally, shipping calculation is only available in the cart.

To calculate shipping costs on product page, three things are necessary: A product with valid dimensions, the quantity and the destination postcode.

Here's what it does before getting to the getCostPerShippingMethod() method bellow:

  • Receives a REST request
  • Sanitizes and validates it
  • Generate the Payload object (which extracts product dimensions, etc)
  • Determines Shipping Zone and Shipping Methods (Example: We offer UPS for postcode X and also Local Pickup for postcode Y)
  • Passes an array of Shipping Methods to getCostPerShippingMethod() bellow.

Then, at getCostPerShippingMethod():

  • Create a Package object for it, which calculates cubage according to product dimensions, quantity and shipping method rules (each shipping method may calculate cubage differently)
  • Instantiate a Handler for this shipping method, which is a internal class prepared to handle the external shipping method calculation rules
  • Handler validates the package dimensions per shipping method. (Example: Local pickup: no limit | UPS: max 30kg, 200cm height, etc)
  • Then it calls the Handler's calculate method, which does it's magic depending on the Shipping Method and payload requested and return the shipping costs

The array returned by getCostPerShippingMethod() is then cascaded down to the frontend to be displayed to the user.

/**
 * Calculates shipping costs for an array of shipping methods
 *
 * @param array $shipping_methods
 * @param Payload $payload
 * @return array
 */
public static function getCostPerShippingMethod(array $shipping_methods, Payload $payload)
{
    $instance = new self;
    $shipping_costs = array();

    foreach ($shipping_methods as $shipping_method) {
        $shipping_method_slug = sanitize_title(get_class($shipping_method));
        $response = new Response($shipping_method);

        try {
            // Create Package based on product and quantities per Shipping Method
            $package = Package::makeFrom($payload->getProduct(), $payload->getQuantity(), $shipping_method);
            $payload->setPackage($package);

            // Create CFPP handler for this Shipping Method
            $cfpp_handler = Factory::createHandler($shipping_method);

            // Gives a chance to set rules, then validate Payload per Shipping Method
            $cfpp_handler->beforeValidate()->validate($payload);

            // Calculate Costs
            do_action('cfpp_before_calculate_cost', $payload, $shipping_method);
            $shipping_costs[] = apply_filters('cfpp_response_success_' . $shipping_method_slug, $cfpp_handler->calculate($payload));

        } catch(PackageException $e) {
            do_action('cfpp_response_package_exception', $shipping_method_slug);
            $shipping_costs[] = $response->error($e->getMessage());
        } catch (FactoryException $e) {
            do_action('cfpp_response_factory_exception', $shipping_method_slug);
            $shipping_costs[] = $response->error($e->getMessage());
        } catch (ValidationErrorException $e) {
            do_action('cfpp_response_validation_exception', $shipping_method_slug);
            $shipping_costs[] = $response->error($e->getMessage());
        } catch (HandlerException $e) {
            do_action('cfpp_response_handler_exception', $shipping_method_slug);
            $shipping_costs[] = $response->error($e->getMessage());
        }
    }

    // Successes first, errors last
    $shipping_costs = $instance->orderShippingCosts($shipping_costs);

    return $shipping_costs;
}

It all works fine. However, I'm having problems testing this class. I can't see how, but this method probably has poor architecture.

How can I improve this code to make it more testable and architecturally correct?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.