Finished up VAT validation for Plans page
This commit is contained in:
parent
94bbd3c8a5
commit
18c828defd
|
@ -1,7 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
define('VAT_RATE', 19.00);
|
||||||
|
|
||||||
class BillingController extends Zend_Controller_Action {
|
class BillingController extends Zend_Controller_Action {
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
//Two of the actions in this controller return JSON because they're used for AJAX:
|
||||||
|
$ajaxContext = $this->_helper->getHelper('AjaxContext');
|
||||||
|
$ajaxContext->addActionContext('vat-validator', 'json')
|
||||||
|
->addActionContext('is-country-in-eu', 'json')
|
||||||
|
->initContext();
|
||||||
|
}
|
||||||
|
|
||||||
public function indexAction()
|
public function indexAction()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -24,12 +35,13 @@ class BillingController extends Zend_Controller_Action {
|
||||||
* validate it somehow. We'll also need to make sure the country given is
|
* validate it somehow. We'll also need to make sure the country given is
|
||||||
* in the EU
|
* in the EU
|
||||||
*/
|
*/
|
||||||
$apply_vat = false;
|
|
||||||
|
|
||||||
$formData = $request->getPost();
|
$formData = $request->getPost();
|
||||||
if ($form->isValid($formData)) {
|
if ($form->isValid($formData)) {
|
||||||
$credentials = self::getAPICredentials();
|
$credentials = self::getAPICredentials();
|
||||||
|
|
||||||
|
$apply_vat = BillingController::checkIfVatShouldBeApplied($formData["customfields"]["7"], $formData["country"]);
|
||||||
|
|
||||||
$postfields = array();
|
$postfields = array();
|
||||||
$postfields["username"] = $credentials["username"];
|
$postfields["username"] = $credentials["username"];
|
||||||
$postfields["password"] = md5($credentials["password"]);
|
$postfields["password"] = md5($credentials["password"]);
|
||||||
|
@ -91,6 +103,124 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$this->view->form = $form;
|
$this->view->form = $form;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function isCountryInEuAction()
|
||||||
|
{
|
||||||
|
// Disable the view and the layout
|
||||||
|
$this->view->layout()->disableLayout();
|
||||||
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
if (!$request->isPost()) {
|
||||||
|
throw new Exception("Must POST data to isCountryInEuAction.");
|
||||||
|
}
|
||||||
|
$formData = $request->getPost();
|
||||||
|
|
||||||
|
//Set the return JSON value
|
||||||
|
$this->_helper->json(array("result"=>BillingController::isCountryInEU($formData["country"])));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function vatValidatorAction()
|
||||||
|
{
|
||||||
|
// Disable the view and the layout
|
||||||
|
$this->view->layout()->disableLayout();
|
||||||
|
$this->_helper->viewRenderer->setNoRender(true);
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
if (!$request->isPost()) {
|
||||||
|
throw new Exception("Must POST data to vatValidatorAction.");
|
||||||
|
}
|
||||||
|
$formData = $request->getPost();
|
||||||
|
|
||||||
|
$vatNumber = trim($formData["vatnumber"]);
|
||||||
|
if (empty($vatNumber)) {
|
||||||
|
$this->_helper->json(array("result"=>false));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set the return JSON value
|
||||||
|
$this->_helper->json(array("result"=>BillingController::checkIfVatShouldBeApplied($vatNumber, $formData["country"])));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if VAT should be applied to the order, false otherwise.
|
||||||
|
*/
|
||||||
|
private static function checkIfVatShouldBeApplied($vatNumber, $countryCode)
|
||||||
|
{
|
||||||
|
if ($countryCode === 'UK') {
|
||||||
|
$countryCode = 'GB'; //VIES database has it as GB
|
||||||
|
}
|
||||||
|
//We don't charge you VAT if you're not in the EU
|
||||||
|
if (!BillingController::isCountryInEU($countryCode))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//So by here, we know you're in the EU.
|
||||||
|
|
||||||
|
//No VAT number? Then we charge you VAT.
|
||||||
|
if (empty($vatNumber)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//Check if VAT number is valid
|
||||||
|
return BillingController::validateVATNumber($vatNumber, $countryCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isCountryInEU($countryCode)
|
||||||
|
{
|
||||||
|
$euCountryCodes = array('BE', 'BG', 'CZ', 'DK', 'DE', 'EE', 'IE', 'EL', 'ES', 'FR',
|
||||||
|
'HR', 'IT', 'CY', 'LV', 'LT', 'LU', 'HU', 'MT', 'NL', 'AT',
|
||||||
|
'PL', 'PT', 'RO', 'SI', 'SK', 'FI', 'SE', 'UK', 'GB');
|
||||||
|
|
||||||
|
if (!in_array($countryCode, $euCountryCodes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an EU VAT number is valid, using the EU VIES validation web API.
|
||||||
|
*
|
||||||
|
* @param string $vatNumber - A VAT identifier (number), with or without the two letter country code at the
|
||||||
|
* start (either one works) .
|
||||||
|
* @param string $countryCode - A two letter country code
|
||||||
|
* @return boolean true if the VAT number is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
private static function validateVATNumber($vatNumber, $countryCode)
|
||||||
|
{
|
||||||
|
$vatNumber = str_replace(array(' ', '.', '-', ',', ', '), '', trim($vatNumber));
|
||||||
|
|
||||||
|
//If the first two letters are a country code, use that as the country code and remove those letters.
|
||||||
|
$firstTwoCharacters = substr($vatNumber, 0, 2);
|
||||||
|
if (preg_match("/[a-zA-Z][a-zA-Z]/", $firstTwoCharacters) === 1) {
|
||||||
|
$countryCode = strtoupper($firstTwoCharacters); //The country code from the VAT number overrides your country.
|
||||||
|
$vatNumber = substr($vatNumber, 2);
|
||||||
|
}
|
||||||
|
$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");
|
||||||
|
|
||||||
|
if($client){
|
||||||
|
$params = array('countryCode' => $countryCode, 'vatNumber' => $vatNumber);
|
||||||
|
try{
|
||||||
|
$r = $client->checkVat($params);
|
||||||
|
if($r->valid == true){
|
||||||
|
// VAT-ID is valid
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// VAT-ID is NOT valid
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(SoapFault $e) {
|
||||||
|
Logging::error('VIES EU VAT validation error: '.$e->faultstring);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Connection to host not possible, europe.eu down?
|
||||||
|
Logging::error('VIES EU VAT validation error: Host unreachable');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private function addVatToInvoice($invoice_id)
|
private function addVatToInvoice($invoice_id)
|
||||||
{
|
{
|
||||||
|
@ -111,8 +241,7 @@ class BillingController extends Zend_Controller_Action {
|
||||||
//TODO: error checking
|
//TODO: error checking
|
||||||
$result = $this->makeRequest($credentials["url"], $invoice_query_string);
|
$result = $this->makeRequest($credentials["url"], $invoice_query_string);
|
||||||
|
|
||||||
$vat_rate = 19.00;
|
$vat_amount = $result["subtotal"] * (VAT_RATE/100);
|
||||||
$vat_amount = $result["subtotal"] * ($vat_rate/100);
|
|
||||||
$invoice_total = $result["total"] + $vat_amount;
|
$invoice_total = $result["total"] + $vat_amount;
|
||||||
|
|
||||||
//Second, update the invoice with the VAT amount and updated total
|
//Second, update the invoice with the VAT amount and updated total
|
||||||
|
@ -254,7 +383,6 @@ class BillingController extends Zend_Controller_Action {
|
||||||
self::viewInvoice($invoice_id);
|
self::viewInvoice($invoice_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: this does not return a service id. why?
|
|
||||||
private static function getClientInstanceId()
|
private static function getClientInstanceId()
|
||||||
{
|
{
|
||||||
$credentials = self::getAPICredentials();
|
$credentials = self::getAPICredentials();
|
||||||
|
@ -272,11 +400,15 @@ class BillingController extends Zend_Controller_Action {
|
||||||
$result = self::makeRequest($credentials["url"], $query_string);
|
$result = self::makeRequest($credentials["url"], $query_string);
|
||||||
Logging::info($result);
|
Logging::info($result);
|
||||||
|
|
||||||
|
//XXX: Debugging / local testing
|
||||||
if ($_SERVER['SERVER_NAME'] == "airtime.localhost") {
|
if ($_SERVER['SERVER_NAME'] == "airtime.localhost") {
|
||||||
return "1384";
|
return "1384";
|
||||||
}
|
}
|
||||||
|
|
||||||
//This code must run on airtime.pro for it to work... it's trying to match
|
//This code must run on airtime.pro for it to work... it's trying to match
|
||||||
//the server's hostname with the client subdomain.
|
//the server's hostname with the client subdomain. Once it finds a match
|
||||||
|
//between the product and the server's hostname/subdomain, then it
|
||||||
|
//returns the ID of that product (aka. the service ID of an Airtime instance)
|
||||||
foreach ($result["products"] as $product)
|
foreach ($result["products"] as $product)
|
||||||
{
|
{
|
||||||
if (strpos($product[0]["groupname"], "Airtime") === FALSE)
|
if (strpos($product[0]["groupname"], "Airtime") === FALSE)
|
||||||
|
|
|
@ -4,9 +4,14 @@
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
<?php echo("var products = " . json_encode(BillingController::getProducts()) . ";");
|
<?php echo("var products = " . json_encode(BillingController::getProducts()) . ";\n");
|
||||||
|
echo("var vatRate = " . json_encode(VAT_RATE) . ";");
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
var vatFieldId = "#customfields-7";
|
||||||
|
var validVATNumber = false;
|
||||||
|
var customerInEU = false;
|
||||||
|
|
||||||
//Disable annual billing for hobbyist plan
|
//Disable annual billing for hobbyist plan
|
||||||
function validatePlan()
|
function validatePlan()
|
||||||
{
|
{
|
||||||
|
@ -20,10 +25,25 @@ function validatePlan()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function recalculateTotal()
|
function validateVATNumber()
|
||||||
{
|
{
|
||||||
console.log(products);
|
$.post("/billing/vat-validator", { "vatnumber" : $(vatFieldId).val(), "country" : $("#country").val() })
|
||||||
|
.success(function(data, textStatus, jqXHR) {
|
||||||
|
if (data["result"]) {
|
||||||
|
$("#vaterror").html("✓ Your VAT number is valid.");
|
||||||
|
window.validVATNumber = true;
|
||||||
|
} else {
|
||||||
|
$("#vaterror").text("Error: Your VAT number is invalid.");
|
||||||
|
window.validVATNumber = false;
|
||||||
|
}
|
||||||
|
recalculateTotals();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recalculate subtotal and total */
|
||||||
|
function recalculateTotals()
|
||||||
|
{
|
||||||
var newProductId = $("input[type='radio'][name='newproductid']:checked");
|
var newProductId = $("input[type='radio'][name='newproductid']:checked");
|
||||||
if (newProductId.length > 0) {
|
if (newProductId.length > 0) {
|
||||||
newProductId = newProductId.val();
|
newProductId = newProductId.val();
|
||||||
|
@ -40,24 +60,99 @@ function recalculateTotal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var total = "0";
|
/** This calculation is all done on the server side too inside WHMCS so don't waste your time
|
||||||
|
trying to hax0r it to get cheap Airtime Pro. */
|
||||||
|
var subtotal = "0";
|
||||||
|
var savings = "0";
|
||||||
|
var subtotalNumber = "0";
|
||||||
|
var billingPeriodString = "";
|
||||||
if ($("#newproductbillingcycle-monthly").is(":checked")) {
|
if ($("#newproductbillingcycle-monthly").is(":checked")) {
|
||||||
total = "$" + newProduct.pricing["USD"]["monthly"] + " per month";
|
billingPeriodString = " per month";
|
||||||
|
subtotalNumber = newProduct.pricing["USD"]["monthly"];
|
||||||
|
subtotal = "$" + subtotalNumber + billingPeriodString;
|
||||||
|
$("#savings").text("");
|
||||||
|
|
||||||
} else if ($("#newproductbillingcycle-annually").is(":checked")) {
|
} else if ($("#newproductbillingcycle-annually").is(":checked")) {
|
||||||
total = "$" + newProduct.pricing["USD"]["annually"] + " per year";
|
subtotalNumber = newProduct.pricing["USD"]["annually"];
|
||||||
|
billingPeriodString = " per year";
|
||||||
|
subtotal = "$" + subtotalNumber + billingPeriodString;
|
||||||
|
savings = "$" + (newProduct.pricing["USD"]["monthly"]*12 - subtotalNumber).toFixed(2);
|
||||||
|
$("#savings").html("You save: " + savings + " per year");
|
||||||
}
|
}
|
||||||
$("#total").text(total);
|
$("#subtotal").text(subtotal);
|
||||||
|
|
||||||
|
//Calculate total:
|
||||||
|
var vatAmount = 0;
|
||||||
|
if (window.customerInEU && !window.validVATNumber) {
|
||||||
|
vatAmount = (parseFloat(subtotalNumber) * vatRate)/100.00;
|
||||||
|
}
|
||||||
|
var total = (vatAmount + parseFloat(subtotalNumber)).toFixed(2);
|
||||||
|
$(".subtotal").text(subtotal);
|
||||||
|
if (vatAmount > 0) {
|
||||||
|
$("#tax").text("Plus VAT at " + parseInt(vatRate) + "%: $" + vatAmount.toFixed(2) + billingPeriodString);
|
||||||
|
} else {
|
||||||
|
$("#tax").text("");
|
||||||
|
}
|
||||||
|
$("#total").text("$" + total + billingPeriodString);
|
||||||
|
}
|
||||||
|
|
||||||
|
function configureByCountry(countryCode)
|
||||||
|
{
|
||||||
|
//Disable the VAT tax field if the country is not in the EU.
|
||||||
|
$.post("/billing/is-country-in-eu", { "country" : countryCode })
|
||||||
|
.success(function(data, textStatus, jqXHR) {
|
||||||
|
if (data["result"]) {
|
||||||
|
$(vatFieldId).prop("disabled", false);
|
||||||
|
$(vatFieldId).prop("readonly", false);
|
||||||
|
$(vatFieldId + "-label").removeClass("disabled");
|
||||||
|
$("#vat_disclaimer2").fadeIn(300);
|
||||||
|
window.customerInEU = true;
|
||||||
|
} else {
|
||||||
|
$(vatFieldId).prop("disabled", true);
|
||||||
|
$(vatFieldId).prop("readonly", true);
|
||||||
|
$(vatFieldId).val("");
|
||||||
|
$(vatFieldId + "-label").addClass("disabled");
|
||||||
|
$("#vat_disclaimer2").fadeOut(0);
|
||||||
|
window.customerInEU = false;
|
||||||
|
}
|
||||||
|
recalculateTotals();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
recalculateTotal();
|
|
||||||
|
|
||||||
|
configureByCountry($("#country").val());
|
||||||
|
recalculateTotals();
|
||||||
|
|
||||||
$("input[name='newproductid']").change(function() {
|
$("input[name='newproductid']").change(function() {
|
||||||
validatePlan();
|
validatePlan();
|
||||||
recalculateTotal();
|
recalculateTotals();
|
||||||
});
|
});
|
||||||
$("input[name='newproductbillingcycle']").change(function() {
|
$("input[name='newproductbillingcycle']").change(function() {
|
||||||
recalculateTotal();
|
recalculateTotals();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#country").change(function() {
|
||||||
|
configureByCountry($(this).val());
|
||||||
|
});
|
||||||
|
|
||||||
|
vatFieldChangeTimer = null;
|
||||||
|
$(vatFieldId).change(function() {
|
||||||
|
if (vatFieldChangeTimer) {
|
||||||
|
clearTimeout(vatFieldChangeTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(this).val() == "") {
|
||||||
|
$("#vaterror").text("");
|
||||||
|
window.validVATNumber = false;
|
||||||
|
recalculateTotals();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vatFieldChangeTimer = setTimeout(function() {
|
||||||
|
//TODO: validate VAT number
|
||||||
|
validateVATNumber();
|
||||||
|
recalculateTotals();
|
||||||
|
}, 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#hobbyist_grid_price").text("$" + products[0].pricing["USD"]["monthly"] + " / month");
|
$("#hobbyist_grid_price").text("$" + products[0].pricing["USD"]["monthly"] + " / month");
|
||||||
|
@ -69,7 +164,7 @@ $(document).ready(function() {
|
||||||
|
|
||||||
<div class="ui-widget ui-widget-content block-shadow clearfix padded-strong billing-panel">
|
<div class="ui-widget ui-widget-content block-shadow clearfix padded-strong billing-panel">
|
||||||
<H2><?=_("Account Plans")?></H2>
|
<H2><?=_("Account Plans")?></H2>
|
||||||
<H3><?=_("Upgrade today and get more listeners and storage space!")?></H3>
|
<H4><?=_("Upgrade today to get more listeners and storage space!")?></H4>
|
||||||
<div class="pricing-grid">
|
<div class="pricing-grid">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -170,10 +265,14 @@ $(document).ready(function() {
|
||||||
Save 15% on annual plans (Hobbyist plan excluded).
|
Save 15% on annual plans (Hobbyist plan excluded).
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
<div id="total_box"><b>Total:</b><br><span id="total"></span></div>
|
<div id="subtotal_box">
|
||||||
|
<b>Subtotal:</b><br>
|
||||||
|
<span class="subtotal"></span><br>
|
||||||
|
<div id="savings"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="vat_disclaimer">
|
<div id="vat_disclaimer">
|
||||||
Plus VAT if you are an EU resident without a valid VAT number.
|
VAT will be added below if you are an EU resident without a valid VAT number.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Enter your payment details:</h3>
|
<h3>Enter your payment details:</h3>
|
||||||
|
@ -226,16 +325,16 @@ $(document).ready(function() {
|
||||||
<div>
|
<div>
|
||||||
<?=$billingForm->securityqans?>
|
<?=$billingForm->securityqans?>
|
||||||
</div>
|
</div>
|
||||||
<div style="float:right; width: 200px;"><p>VAT will be added to your invoice if you are an EU resident without a valid VAT number.</p>
|
<div id="vat_disclaimer2"><p>VAT will be added to your invoice if you are an EU resident without a valid company VAT number.</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<?=$billingForm->getElement("7"); ?>
|
<?=$billingForm->getElement("7"); ?>
|
||||||
|
<div id="vaterror"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<?php //$billingForm->getElement("71"); ?>
|
<div class="billing_checkbox">
|
||||||
<div class="billing_checkbox">
|
|
||||||
<?=$billingForm->getElement("71")->renderViewHelper(); ?>
|
<?=$billingForm->getElement("71")->renderViewHelper(); ?>
|
||||||
</div>
|
</div>
|
||||||
<?=$billingForm->getElement("71")->renderLabel(); ?>
|
<?=$billingForm->getElement("71")->renderLabel(); ?>
|
||||||
|
@ -249,6 +348,12 @@ $(document).ready(function() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
<div id="total_box">
|
||||||
|
<b>Subtotal:</b> <span class="subtotal"></span><br>
|
||||||
|
<span id="tax"></span><br>
|
||||||
|
<b>Total:</b> <span id="total"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<input type="submit" value="Submit Order"></input>
|
<input type="submit" value="Submit Order"></input>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -7,6 +7,19 @@
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.billing-panel h3
|
||||||
|
{
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.billing-panel h4
|
||||||
|
{
|
||||||
|
font-size: 1.25em;
|
||||||
|
margin: 0px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
#upgrade-downgrade
|
#upgrade-downgrade
|
||||||
{
|
{
|
||||||
border: 0px solid #000;
|
border: 0px solid #000;
|
||||||
|
@ -105,8 +118,15 @@
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#total_box
|
#vat_disclaimer2
|
||||||
{
|
{
|
||||||
|
float:right;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#subtotal_box, #total_box
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
@ -114,6 +134,23 @@
|
||||||
background: #ccc;
|
background: #ccc;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
#total_box
|
||||||
|
{
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#total
|
||||||
|
{
|
||||||
|
border-bottom: 3px double;
|
||||||
|
}
|
||||||
|
|
||||||
|
#savings
|
||||||
|
{
|
||||||
|
/*line-height: 30px;*/
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
#paymentmethod
|
#paymentmethod
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue