verbb / postie

A Craft Commerce shipping calculator plugin.
Other
12 stars 18 forks source link

FR: Address validation & suggestions #26

Open Mosnar opened 4 years ago

Mosnar commented 4 years ago

Description

I would love to see native address validation from the provider. I've been achieving this myself by creating my own validator and attaching it when rules are defined:

<?php

namespace modules\mymodule\validators;

use craft\commerce\models\Address;
use Exception;
use Ups\AddressValidation;
use verbb\postie\Postie;
use verbb\postie\providers\UPS;
use verbb\postie\services\Providers;
use yii\validators\Validator;

class UpsAddressValidator extends Validator
{
    /**
     * @param Address $model
     * @param string $attribute
     */
    public function validateAttribute($model, $attribute)
    {
        $address = new \Ups\Entity\Address();
        $address->setAddressLine1($model->address1);
        $address->setAddressLine2($model->address2);
        $address->setAddressLine3($model->address3);
        $address->setStateProvinceCode($model->getState()->abbreviation);
        $address->setCity($model->city);
        if ($model->country !== null) {
            $address->setCountryCode($model->country->iso);
        } else {
            $address->setCountryCode('US');
        }
        $address->setPostalCode($model->zipCode);
        /** @var Providers $providers */
        $providers = Postie::getInstance()->getProviders();
        /** @var UPS $ups */
        $ups = $providers->getProviderByHandle('ups');
        $settingsContainer = $ups->getSettings();
        $settings = $settingsContainer['settings'];
        $xav = new AddressValidation($settings['apiKey'], $settings['username'], $settings['password']);
        $xav->activateReturnObjectOnValidate();
        try {
            $response = $xav->validate($address, $requestOption = AddressValidation::REQUEST_OPTION_ADDRESS_VALIDATION, $maxSuggestion = 15);
            if (!$response->isValid()) {
                $model->addError('fullAddress', 'We could not verify your address. Please review and try again.');
            }
        } catch (Exception $e) {
            $model->addError('fullAddress', 'We could not validate your address');
        }
    }
}
if (!Craft::$app->request->isCpRequest && !Craft::$app->request->isConsoleRequest) {
            Event::on(Address::class, Address::EVENT_DEFINE_RULES, function (DefineRulesEvent $event) {
                $event->rules[] = [['address1'], UpsAddressValidator::class];
            });
        }

My plan was/is to add address suggestions by attaching a behavior to the Address model with an array of Commerce Address models populated from the UPS suggested addresses then populating the behavior in the validator. On the frontend, you could then render our suggested addresses the same way you render any other address and even allow the user to accept your suggested address.

Additional info