Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions assets/js/certificate-table.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
( function( $ ) {
var script_data = SST_Certificate_Table_Data;
jQuery( function( $ ) {
var script_data = window.SST_Certificate_Table_Data || { strings: {}, certificates: {}, user_id: 0 };
var $row_template = wp.template( 'sst-certificate-row' );
var $blank_template = wp.template( 'sst-certificate-row-blank' );

Expand Down Expand Up @@ -246,4 +246,4 @@
user_id: script_data.user_id,
certificates: script_data.certificates,
} );
} )( jQuery );
} );
22 changes: 14 additions & 8 deletions assets/js/checkout.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
/* global jQuery */
jQuery( function( $ ) {
jQuery(function ($) {
// Update checkout totals when certificate changes.
function updateCheckoutTotals() {
$( document.body ).trigger( 'update_checkout' );
jQuery(document.body).trigger('update_checkout');
}

// Toggle visibility of tax details form based on value of "Tax exempt?" checkbox.
$( document ).on( 'change', '#certificate_id', function() {
$( '#exempt_certificate_form' ).toggle(
$( '#certificate_id' ).val() === 'new'
jQuery(document).on('change', '#certificate_id', function () {
// If the value is 'none', hide the form and return.
if (jQuery(this).val() === 'none') {
jQuery('#exempt_certificate_form').hide();
return;
}

jQuery('#exempt_certificate_form').toggle(
jQuery('#certificate_id').val() === 'new'
);

updateCheckoutTotals();
} );
});

$( '#certificate_id' ).trigger( 'change' );
} );
jQuery('#certificate_id').trigger('change');
});
186 changes: 169 additions & 17 deletions includes/class-sst-certificates.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ protected static function get_certificate_description( $detail ) {
public static function get_certificates_formatted( $user_id = 0 ) {
$certificates = array();
foreach ( self::get_certificates( $user_id ) as $id => $raw_cert ) {
if ( empty( $id ) ) {
continue;
}
$certificates[ $id ] = self::format_certificate( $raw_cert );
}

Expand Down Expand Up @@ -203,18 +206,46 @@ private static function fetch_certificates( $user_id = 0 ) {
if ( ! $user_id ) {
$user = wp_get_current_user();
} else {
$user = new WP_User( $user_id );
$user = new \WP_User( $user_id );
}

if ( ! isset( $user->ID ) ) {
return array(); /* Invalid user ID. */
}

try {
$request = new TaxCloud\Request\GetExemptCertificates(
if ( sst_get_api_version() === 'v3' ) {

$v3_exemptions = new \TaxCloud_V3\Exemptions();
$final_certs = array();

// Try fetching by ID and Username to catch legacy certificates
$lookup_ids = array( (string) $user->ID, $user->user_login );

foreach ( $lookup_ids as $lookup_id ) {
$response = $v3_exemptions->get_certificates( array(
'customerId' => $lookup_id,
) );

if ( ! is_wp_error( $response ) && isset( $response['items'] ) && is_array( $response['items'] ) ) {
foreach ( $response['items'] as $item ) {
if ( empty( $item['singlePurchase'] ) ) { /* Skip single certs */
$cert = self::build_v1_cert_from_v3( $item );
$final_certs[ $cert->getCertificateID() ] = $cert;
}
}
}
}

return $final_certs;
}



$request = new \TaxCloud\Request\GetExemptCertificates(
SST_Settings::get( 'tc_id' ),
SST_Settings::get( 'tc_key' ),
$user->user_login
$user->ID
);

$certificates = TaxCloud()->GetExemptCertificates( $request );
Expand All @@ -229,11 +260,88 @@ private static function fetch_certificates( $user_id = 0 ) {
}

return $final_certs;
} catch ( Exception $ex ) {
} catch ( \Exception $ex ) {
return array();
}
}

/**
* Convert TaxCloud v3 exemption certificate format to equivalent v1.
*
* @param array $v3_cert V3 certificate formatted as array.
* @return \TaxCloud\ExemptionCertificate
*/
public static function build_v1_cert_from_v3( $v3_cert ) {
$name_parts = explode( ' ', $v3_cert['customerName'] ?? '', 2 );
$first_name = $name_parts[0];
$last_name = isset( $name_parts[1] ) ? $name_parts[1] : '';

$v3_reason = $v3_cert['reason'] ?? '';
$reason_map = array(
'ReligiousOrganization' => 'ReligiousOrEducationalOrganization',
'EducationalOrganization' => 'ReligiousOrEducationalOrganization',
'FederalGovernment' => 'FederalGovernmentDepartment',
'StateOrLocalGovernment' => 'StateOrLocalGovernmentName',
'TribalGovernment' => 'TribalGovernmentName',
'IndustrialProduction' => 'IndustrialProductionOrManufacturing',
);
$v1_reason = isset( $reason_map[ $v3_reason ] ) ? $reason_map[ $v3_reason ] : $v3_reason;
if ( ! defined( '\TaxCloud\ExemptionReason::' . $v1_reason ) ) {
$v1_reason = 'Other';
}

$exempt_states = array();
if ( isset( $v3_cert['states'] ) && is_array( $v3_cert['states'] ) ) {
foreach ( $v3_cert['states'] as $state ) {
$abbr = $state['abbreviation'] ?? '';
if ( ! defined( '\TaxCloud\State::' . $abbr ) ) {
continue; // Skip invalid states
}

$exempt_states[] = array(
'StateAbbr' => $abbr,
'ReasonForExemption' => $v1_reason,
'IdentificationNumber' => '',
);
}
}

// TaxType and BusinessType mapped similarly
$v3_business_type = $v3_cert['customerBusinessType'] ?? '';
if ( ! defined( '\TaxCloud\BusinessType::' . $v3_business_type ) ) {
$v3_business_type = 'Other';
}

$v1_cert = array(
'CertificateID' => $v3_cert['certificateId'] ?? '',
'Detail' => array(
'ExemptStates' => $exempt_states,
'PurchaserTaxID' => array(
'TaxType' => 'FEIN',
'IDNumber' => '',
'StateOfIssue' => '',
),
'SinglePurchase' => $v3_cert['singlePurchase'] ?? false,
'SinglePurchaseOrderNumber' => '',
'PurchaserFirstName' => $first_name,
'PurchaserLastName' => $last_name,
'PurchaserTitle' => '',
'PurchaserAddress1' => $v3_cert['address']['line1'] ?? '',
'PurchaserAddress2' => $v3_cert['address']['line2'] ?? '',
'PurchaserCity' => $v3_cert['address']['city'] ?? '',
'PurchaserState' => $v3_cert['address']['state'] ?? '',
'PurchaserZip' => $v3_cert['address']['zip'] ?? '',
'PurchaserBusinessType' => $v3_business_type,
'PurchaserBusinessTypeOtherValue' => $v3_cert['customerBusinessDescription'] ?? '',
'PurchaserExemptionReason' => $v1_reason,
'PurchaserExemptionReasonValue' => $v3_cert['reasonDescription'] ?? '',
'CreatedDate' => $v3_cert['createdDate'] ?? gmdate( 'c' ),
),
);

return \TaxCloud\ExemptionCertificate::fromArray( $v1_cert );
}

/**
* Delete the customer's cached certificates.
*
Expand Down Expand Up @@ -330,14 +438,49 @@ public static function add_certificate( $certificate, $purchaser, $user_id = 0 )
}

// Add certificate
$request = new TaxCloud\Request\AddExemptCertificate(
SST_Settings::get( 'tc_id' ),
SST_Settings::get( 'tc_key' ),
$user->user_login, // TODO: use user ID instead?
$certificate
);
if ( sst_get_api_version() === 'v3' ) {
$detail = $certificate->getDetail();

$states = array();
foreach ( $detail->getExemptStates() as $state ) {
$states[] = array( 'abbreviation' => $state->getStateAbbr() );
}

$v3_args = array(
'customerId' => (string) $user->ID,
'customerName' => trim( $detail->getPurchaserFirstName() . ' ' . $detail->getPurchaserLastName() ),
'customerBusinessType' => $detail->getPurchaserBusinessType() ?: 'Other',
'customerBusinessDescription' => $detail->getPurchaserBusinessTypeOtherValue(),
'reason' => $detail->getPurchaserExemptionReason() ?: 'Other',
'reasonDescription' => $detail->getPurchaserExemptionReasonValue(),
'address' => array(
'line1' => $detail->getPurchaserAddress1(),
'line2' => $detail->getPurchaserAddress2(),
'city' => $detail->getPurchaserCity(),
'state' => $detail->getPurchaserState(),
'zip' => substr( $detail->getPurchaserZip(), 0, 5 ),
),
'states' => $states
);

$v3_exemptions = new \TaxCloud_V3\Exemptions();
$response = $v3_exemptions->create_certificate( $v3_args );

if ( is_wp_error( $response ) ) {
throw new \Exception( $response->get_error_message() );
}

$certificate_id = $response['certificateId'];
} else {
$request = new \TaxCloud\Request\AddExemptCertificate(
SST_Settings::get( 'tc_id' ),
SST_Settings::get( 'tc_key' ),
$user->ID,
$certificate
);

$certificate_id = TaxCloud()->AddExemptCertificate( $request );
$certificate_id = TaxCloud()->AddExemptCertificate( $request );
}

// Invalidate cached certificates
SST_Certificates::delete_certificates( $user->ID );
Expand Down Expand Up @@ -376,13 +519,22 @@ public static function delete_certificate( $certificate_id, $user_id = 0 ) {
throw new Exception( 'Unauthorized' );
}

$request = new TaxCloud\Request\DeleteExemptCertificate(
SST_Settings::get( 'tc_id' ),
SST_Settings::get( 'tc_key' ),
$certificate_id
);
if ( sst_get_api_version() === 'v3' ) {
$v3_exemptions = new \TaxCloud_V3\Exemptions();
$response = $v3_exemptions->delete_certificate( $certificate_id );

TaxCloud()->DeleteExemptCertificate( $request );
if ( is_wp_error( $response ) ) {
throw new \Exception( $response->get_error_message() );
}
} else {
$request = new \TaxCloud\Request\DeleteExemptCertificate(
SST_Settings::get( 'tc_id' ),
SST_Settings::get( 'tc_key' ),
$certificate_id
);

TaxCloud()->DeleteExemptCertificate( $request );
}

// Invalidate cached certificates.
SST_Certificates::delete_certificates( $user_id );
Expand Down
16 changes: 12 additions & 4 deletions includes/frontend/class-sst-checkout.php
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ protected function get_post_data() {
public function get_certificate() {
$certificate_id = $this->get_certificate_id();

if ( $certificate_id ) {
if ( $certificate_id && 'none' !== $certificate_id ) {
// Apply saved entity-based cert
return new ExemptionCertificateBase( $certificate_id );
}
Expand Down Expand Up @@ -572,7 +572,15 @@ public function init_certificate_id() {
$certificate_id = sanitize_text_field(
wp_unslash( $post_data['certificate_id'] )
);
WC()->session->set( 'sst_certificate_id', $certificate_id );

if ( 'none' === $certificate_id ) {
$certificate_id = '';
}

if ( $certificate_id !== WC()->session->get( 'sst_certificate_id' ) ) {
WC()->session->set( 'sst_certificate_id', $certificate_id );
WC()->session->set( 'sst_packages', array() ); // Clear cache on selection change
}
} else if ( is_null( WC()->session->sst_certificate_id ) ) {
WC()->session->set(
'sst_certificate_id',
Expand Down Expand Up @@ -879,8 +887,8 @@ public function output_exemption_form() {

$certificates = SST_Certificates::get_certificates_formatted();
$options = array(
'' => 'None',
'new' => 'Add new certificate',
'none' => __( 'Select a exemption certificate', 'simple-sales-tax' ),
'new' => __( 'Add new certificate', 'simple-sales-tax' ),
);

foreach ( $certificates as $cert ) {
Expand Down
9 changes: 9 additions & 0 deletions includes/sst-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -581,4 +581,13 @@ function sst_get_rate_code() {
function sst_integration_mode() {
$data_mover = SST_Settings::get( 'data_mover', false );
return $data_mover == false ? 'realtime' : 'data_mover';
}

/**
* Get the API version.
*
* @return string API version
*/
function sst_get_api_version() {
return 'v3';
}
Loading
Loading