Version Notes
First stable release.
Download this release
Release Info
Developer | Billy's Billing |
Extension | Billys_Billing_Invoicer |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- app/code/community/BillysBilling/.DS_Store +0 -0
- app/code/community/BillysBilling/Invoicer/.DS_Store +0 -0
- app/code/community/BillysBilling/Invoicer/Helper/Data.php +6 -0
- app/code/community/BillysBilling/Invoicer/Model/.DS_Store +0 -0
- app/code/community/BillysBilling/Invoicer/Model/Accounts.php +65 -0
- app/code/community/BillysBilling/Invoicer/Model/Observer.php +215 -0
- app/code/community/BillysBilling/Invoicer/Model/Products.php +54 -0
- app/code/community/BillysBilling/Invoicer/Model/VatModels.php +54 -0
- app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/.DS_Store +0 -0
- app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/Billy/Client.php +67 -0
- app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/Billy/Exception.php +16 -0
- app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/Billy/Request.php +100 -0
- app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/bootstrap.php +11 -0
- app/code/community/BillysBilling/Invoicer/etc/config.xml +53 -0
- app/code/community/BillysBilling/Invoicer/etc/system.xml +72 -0
- app/etc/modules/BillysBilling_Invoicer.xml +8 -0
- package.xml +25 -0
app/code/community/BillysBilling/.DS_Store
ADDED
Binary file
|
app/code/community/BillysBilling/Invoicer/.DS_Store
ADDED
Binary file
|
app/code/community/BillysBilling/Invoicer/Helper/Data.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class BillysBilling_Invoicer_Helper_Data extends Mage_Core_Helper_Abstract {
|
3 |
+
public static function printError($e, $msg = null) {
|
4 |
+
Mage::getSingleton("core/session")->addError("Billy Exception: " . $e->getMessage() . " (" . $e->getHelpUrl() . ")" . ($msg == null ? "" : "<br>Message: " . $msg));
|
5 |
+
}
|
6 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/.DS_Store
ADDED
Binary file
|
app/code/community/BillysBilling/Invoicer/Model/Accounts.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class BillysBilling_Invoicer_Model_Accounts {
|
3 |
+
public function toOptionArray() {
|
4 |
+
if (!Mage::getStoreConfig("billy/api/api_key") || strlen(Mage::getStoreConfig("billy/api/api_key")) < 10) {
|
5 |
+
return array(
|
6 |
+
array(
|
7 |
+
"value" => "",
|
8 |
+
"label" => "Please enter API key above and Save Config"
|
9 |
+
)
|
10 |
+
);
|
11 |
+
}
|
12 |
+
// Include Billy's PHP SDK
|
13 |
+
if (!class_exists('Billy_Client', false)) {
|
14 |
+
require(dirname(__FILE__) . "/billysbilling-php/bootstrap.php");
|
15 |
+
}
|
16 |
+
|
17 |
+
// Create new client with API key
|
18 |
+
try {
|
19 |
+
$client = new Billy_Client(Mage::getStoreConfig("billy/api/api_key"));
|
20 |
+
} catch (Billy_Exception $e) {
|
21 |
+
BillysBilling_Invoicer_Helper_Data::printError($e);
|
22 |
+
return array(
|
23 |
+
array(
|
24 |
+
"value" => "",
|
25 |
+
"label" => "Please use a valid API key"
|
26 |
+
)
|
27 |
+
);
|
28 |
+
}
|
29 |
+
|
30 |
+
// Get all accounts
|
31 |
+
try {
|
32 |
+
$response = $client->get("accounts");
|
33 |
+
} catch (Billy_Exception $e) {
|
34 |
+
BillysBilling_Invoicer_Helper_Data::printError($e, "Error occurred on getting accounts data");
|
35 |
+
return array(
|
36 |
+
array(
|
37 |
+
"value" => "",
|
38 |
+
"label" => "Could not retrieve accounts from Billy API"
|
39 |
+
)
|
40 |
+
);
|
41 |
+
}
|
42 |
+
|
43 |
+
// Map accounts to account types and sort account types
|
44 |
+
$results = array();
|
45 |
+
foreach ($response->accounts AS $account) {
|
46 |
+
$results[$account->accountType->name][$account->name] = array(
|
47 |
+
"value" => $account->id,
|
48 |
+
"label" => $account->name
|
49 |
+
);
|
50 |
+
}
|
51 |
+
ksort($results);
|
52 |
+
|
53 |
+
// Create optgroups and options containing account types and accounts
|
54 |
+
$options = array();
|
55 |
+
foreach ($results AS $accountType => $accounts) {
|
56 |
+
ksort($accounts);
|
57 |
+
$options[] = array(
|
58 |
+
"value" => $accounts,
|
59 |
+
"label" => $accountType
|
60 |
+
);
|
61 |
+
}
|
62 |
+
|
63 |
+
return $options;
|
64 |
+
}
|
65 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/Observer.php
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class BillysBilling_Invoicer_Model_Observer {
|
3 |
+
|
4 |
+
private $testMode = false;
|
5 |
+
|
6 |
+
private $apiKey = "";
|
7 |
+
private $shippingId = "";
|
8 |
+
private $accountId = "";
|
9 |
+
private $vatModelId = "";
|
10 |
+
|
11 |
+
private $client;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Save invoice to BB with contact and product details.
|
15 |
+
*
|
16 |
+
* @event sales_model_service_quote_submit_success
|
17 |
+
*
|
18 |
+
* @param $observer
|
19 |
+
*/
|
20 |
+
public function saveInvoiceOnSuccess($observer) {
|
21 |
+
if (Mage::getStoreConfig("billy/invoicer/mode") && Mage::getStoreConfig("billy/invoicer/mode") == "test") {
|
22 |
+
$this->testMode = true;
|
23 |
+
}
|
24 |
+
|
25 |
+
// Set variables
|
26 |
+
$this->apiKey = Mage::getStoreConfig("billy/api/api_key");
|
27 |
+
$this->shippingId = Mage::getStoreConfig("billy/invoicer/shipping_account");
|
28 |
+
$this->accountId = Mage::getStoreConfig("billy/invoicer/sales_account");
|
29 |
+
$this->vatModelId = Mage::getStoreConfig("billy/invoicer/vat_model");
|
30 |
+
|
31 |
+
// Include Billy's PHP SDK
|
32 |
+
if (!class_exists('Billy_Client', false)) {
|
33 |
+
require(dirname(__FILE__) . "/billysbilling-php/bootstrap.php");
|
34 |
+
}
|
35 |
+
|
36 |
+
// Create new client with API key
|
37 |
+
try {
|
38 |
+
$this->client = new Billy_Client($this->apiKey);
|
39 |
+
} catch (Billy_Exception $e) {
|
40 |
+
BillysBilling_Invoicer_Helper_Data::printError($e);
|
41 |
+
return false;
|
42 |
+
}
|
43 |
+
|
44 |
+
return $this->createInvoice($observer->getOrder());
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Process contacts and products, and create the invoice.
|
49 |
+
*
|
50 |
+
* @param $order
|
51 |
+
* @return array Response from API for invoice creation
|
52 |
+
*/
|
53 |
+
private function createInvoice($order) {
|
54 |
+
// Get contact ID
|
55 |
+
$contactId = $this->insertIgnore("contacts", $order->getBillingAddress());
|
56 |
+
if ($contactId == null) {
|
57 |
+
return false;
|
58 |
+
}
|
59 |
+
|
60 |
+
// Run through each order item
|
61 |
+
$items = $order->getItemsCollection(array(), true);
|
62 |
+
$products = array();
|
63 |
+
foreach ($items as $item) {
|
64 |
+
// Get product ID
|
65 |
+
$productId = $this->insertIgnore("products", $item);
|
66 |
+
if ($productId == null) {
|
67 |
+
return false;
|
68 |
+
}
|
69 |
+
|
70 |
+
// Add item to product array
|
71 |
+
$product = array(
|
72 |
+
"productId" => $productId,
|
73 |
+
"quantity" => $item->getQtyInvoiced(),
|
74 |
+
"unitPrice" => $item->getPrice()
|
75 |
+
);
|
76 |
+
// Apply discounts
|
77 |
+
if ($item->getDiscountPercent() > 0) {
|
78 |
+
$product["discountMode"] = "percent";
|
79 |
+
$product["discountValue"] = $item->getDiscountPercent();
|
80 |
+
} else if ($item->getDiscountAmount() > 0) {
|
81 |
+
$product["discountMode"] = "cash";
|
82 |
+
$product["discountValue"] = $item->getDiscountAmount();
|
83 |
+
}
|
84 |
+
|
85 |
+
$products[] = $product;
|
86 |
+
}
|
87 |
+
// Add shipping costs to product array
|
88 |
+
$products[] = array(
|
89 |
+
"productId" => $this->shippingId,
|
90 |
+
"quantity" => 1,
|
91 |
+
"unitPrice" => $order->getShippingAmount()
|
92 |
+
);
|
93 |
+
|
94 |
+
// Order date
|
95 |
+
$date = date("Y-m-d", $order->getCreatedAtDate()->getTimestamp());
|
96 |
+
// Set invoice data
|
97 |
+
$invoice = array(
|
98 |
+
"type" => "invoice",
|
99 |
+
"contactId" => $contactId,
|
100 |
+
"entryDate" => $date,
|
101 |
+
"dueDate" => $date,
|
102 |
+
"currencyId" => Mage::app()->getStore()->getCurrentCurrencyCode(),
|
103 |
+
"state" => "approved",
|
104 |
+
"lines" => $products
|
105 |
+
);
|
106 |
+
|
107 |
+
// Create new invoice
|
108 |
+
try {
|
109 |
+
if ($this->testMode) {
|
110 |
+
return $this->client->fakePost(Mage::getBaseDir() . "/tests/output.log", "invoices", $invoice);
|
111 |
+
}
|
112 |
+
return $this->client->post("invoices", $invoice);
|
113 |
+
} catch (Billy_Exception $e) {
|
114 |
+
BillysBilling_Invoicer_Helper_Data::printError($e, "Error occurred on invoice creation.");
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Take a data object from Magento, use it to either search for existing entries in BB and return ID of that, or
|
120 |
+
* insert a new entry in BB and return ID of that.
|
121 |
+
*
|
122 |
+
* @param $type string "contacts" or "products"
|
123 |
+
* @param $data BillingAddress object or Item object
|
124 |
+
*
|
125 |
+
* @return int ID of inserted or found entry
|
126 |
+
*/
|
127 |
+
private function insertIgnore($type, $data) {
|
128 |
+
// Format data
|
129 |
+
$data = $this->formatArray($type, $data);
|
130 |
+
|
131 |
+
// Check for existing contact
|
132 |
+
$responseArray = array();
|
133 |
+
$id = null;
|
134 |
+
try {
|
135 |
+
$address = $type . "?q=" . urlencode($data['name']);
|
136 |
+
if ($this->testMode) {
|
137 |
+
$response = $this->client->fakeGet(Mage::getBaseDir() . "/tests/output.log", $address);
|
138 |
+
} else {
|
139 |
+
$response = $this->client->get($address);
|
140 |
+
}
|
141 |
+
$responseArray = $response->$type;
|
142 |
+
} catch (Billy_Exception $e) {
|
143 |
+
BillysBilling_Invoicer_Helper_Data::printError($e, "Error occurred on getting " . $type . " data");
|
144 |
+
}
|
145 |
+
if (count($responseArray) > 0) {
|
146 |
+
// If existing contact, then save ID
|
147 |
+
$id = $responseArray[0]->id;
|
148 |
+
} else {
|
149 |
+
// Create new contact and contact person, then save ID
|
150 |
+
try {
|
151 |
+
if ($this->testMode) {
|
152 |
+
$response = $this->client->fakePost(Mage::getBaseDir() . "/tests/output.log", $type, $data);
|
153 |
+
} else {
|
154 |
+
$response = $this->client->post($type, $data);
|
155 |
+
}
|
156 |
+
$id = $response->id;
|
157 |
+
} catch (Billy_Exception $e) {
|
158 |
+
BillysBilling_Invoicer_Helper_Data::printError($e, "Error occurred on posting " . $type . " data");
|
159 |
+
}
|
160 |
+
}
|
161 |
+
return $id;
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Take a data object from Magento and convert it into something usable by BB API.
|
166 |
+
*
|
167 |
+
* @param $type string "contacts" or "products"
|
168 |
+
* @param $data BillingAddress object or Item object
|
169 |
+
* @return array of either contact or product
|
170 |
+
*/
|
171 |
+
private function formatArray($type, $data) {
|
172 |
+
if ($type == "contacts") {
|
173 |
+
// Set name depending on company or not
|
174 |
+
if ($data->getCompany()) {
|
175 |
+
$name = $data->getCompany();
|
176 |
+
} else {
|
177 |
+
$name = $data->getName();
|
178 |
+
}
|
179 |
+
|
180 |
+
return array(
|
181 |
+
'name' => $name,
|
182 |
+
'street' => $data->getStreetFull(),
|
183 |
+
'zipcode' => $data->getPostcode(),
|
184 |
+
'city' => $data->getCity(),
|
185 |
+
'countryId' => $data->getCountry_id(),
|
186 |
+
'state' => $data->getRegion(),
|
187 |
+
'phone' => $data->getTelephone(),
|
188 |
+
'fax' => $data->getFax(),
|
189 |
+
'persons' => array(
|
190 |
+
array(
|
191 |
+
'name' => $data->getName(),
|
192 |
+
'email' => $data->getEmail(),
|
193 |
+
'phone' => $data->getTelephone()
|
194 |
+
)
|
195 |
+
)
|
196 |
+
);
|
197 |
+
} else if ($type == "products") {
|
198 |
+
return array(
|
199 |
+
"name" => $data->getName(),
|
200 |
+
"accountId" => $this->accountId,
|
201 |
+
"vatModelId" => $this->vatModelId,
|
202 |
+
"productType" => "product",
|
203 |
+
"productNo" => $data->product_id,
|
204 |
+
"suppliersProductNo" => $data->sku,
|
205 |
+
"prices" => array(
|
206 |
+
array(
|
207 |
+
"currencyId" => Mage::app()->getStore()->getCurrentCurrencyCode(),
|
208 |
+
"unitPrice" => $data->getPrice()
|
209 |
+
)
|
210 |
+
)
|
211 |
+
);
|
212 |
+
}
|
213 |
+
return null;
|
214 |
+
}
|
215 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/Products.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class BillysBilling_Invoicer_Model_Products {
|
3 |
+
public function toOptionArray() {
|
4 |
+
if (!Mage::getStoreConfig("billy/api/api_key") || strlen(Mage::getStoreConfig("billy/api/api_key")) < 10) {
|
5 |
+
return array(
|
6 |
+
array(
|
7 |
+
"value" => "",
|
8 |
+
"label" => "Please enter API key above and Save Config"
|
9 |
+
)
|
10 |
+
);
|
11 |
+
}
|
12 |
+
// Include Billy's PHP SDK
|
13 |
+
if (!class_exists('Billy_Client', false)) {
|
14 |
+
require(dirname(__FILE__) . "/billysbilling-php/bootstrap.php");
|
15 |
+
}
|
16 |
+
|
17 |
+
// Create new client with API key
|
18 |
+
try {
|
19 |
+
$client = new Billy_Client(Mage::getStoreConfig("billy/api/api_key"));
|
20 |
+
} catch (Billy_Exception $e) {
|
21 |
+
BillysBilling_Invoicer_Helper_Data::printError($e);
|
22 |
+
return array(
|
23 |
+
array(
|
24 |
+
"value" => "",
|
25 |
+
"label" => "Please use a valid API key"
|
26 |
+
)
|
27 |
+
);
|
28 |
+
}
|
29 |
+
|
30 |
+
// Get all products
|
31 |
+
try {
|
32 |
+
$response = $client->get("products");
|
33 |
+
} catch (Billy_Exception $e) {
|
34 |
+
BillysBilling_Invoicer_Helper_Data::printError($e, "Error occurred on getting products data");
|
35 |
+
return array(
|
36 |
+
array(
|
37 |
+
"value" => "",
|
38 |
+
"label" => "Could not retrieve products from Billy API"
|
39 |
+
)
|
40 |
+
);
|
41 |
+
}
|
42 |
+
|
43 |
+
// Map accounts to account types and sort account types
|
44 |
+
$options = array();
|
45 |
+
foreach ($response->products AS $product) {
|
46 |
+
$options[] = array(
|
47 |
+
"value" => $product->id,
|
48 |
+
"label" => $product->name
|
49 |
+
);
|
50 |
+
}
|
51 |
+
|
52 |
+
return $options;
|
53 |
+
}
|
54 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/VatModels.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class BillysBilling_Invoicer_Model_VatModels {
|
3 |
+
public function toOptionArray() {
|
4 |
+
if (!Mage::getStoreConfig("billy/api/api_key") || strlen(Mage::getStoreConfig("billy/api/api_key")) < 10) {
|
5 |
+
return array(
|
6 |
+
array(
|
7 |
+
"value" => "",
|
8 |
+
"label" => "Please enter API key above and Save Config"
|
9 |
+
)
|
10 |
+
);
|
11 |
+
}
|
12 |
+
// Include Billy's PHP SDK
|
13 |
+
if (!class_exists('Billy_Client', false)) {
|
14 |
+
require(dirname(__FILE__) . "/billysbilling-php/bootstrap.php");
|
15 |
+
}
|
16 |
+
|
17 |
+
// Create new client with API key
|
18 |
+
try {
|
19 |
+
$client = new Billy_Client(Mage::getStoreConfig("billy/api/api_key"));
|
20 |
+
} catch (Billy_Exception $e) {
|
21 |
+
BillysBilling_Invoicer_Helper_Data::printError($e);
|
22 |
+
return array(
|
23 |
+
array(
|
24 |
+
"value" => "",
|
25 |
+
"label" => "Please use a valid API key"
|
26 |
+
)
|
27 |
+
);
|
28 |
+
}
|
29 |
+
|
30 |
+
// Get all VAT models
|
31 |
+
try {
|
32 |
+
$response = $client->get("vatModels");
|
33 |
+
} catch (Billy_Exception $e) {
|
34 |
+
BillysBilling_Invoicer_Helper_Data::printError($e, "Error occurred on getting vat models data");
|
35 |
+
return array(
|
36 |
+
array(
|
37 |
+
"value" => "",
|
38 |
+
"label" => "Could not retrieve vat models from Billy API"
|
39 |
+
)
|
40 |
+
);
|
41 |
+
}
|
42 |
+
|
43 |
+
// Create options containing VAT models
|
44 |
+
$options = array();
|
45 |
+
foreach ($response->vatModels AS $vatModel) {
|
46 |
+
$options[] = array(
|
47 |
+
"value" => $vatModel->id,
|
48 |
+
"label" => $vatModel->name
|
49 |
+
);
|
50 |
+
}
|
51 |
+
|
52 |
+
return $options;
|
53 |
+
}
|
54 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/.DS_Store
ADDED
Binary file
|
app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/Billy/Client.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Billy_Client {
|
3 |
+
|
4 |
+
private $request;
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Construct a Billy Client with an API key and optionally an API version.
|
8 |
+
*
|
9 |
+
* @param string $apiKey API key from Billy
|
10 |
+
* @param string $apiVersion Optional (currently v1)
|
11 |
+
*/
|
12 |
+
public function __construct($apiKey, $apiVersion = "v1") {
|
13 |
+
// Only accept a string of 32 characters containing only lowercase and uppercase letters and numbers
|
14 |
+
if (!preg_match("/^([a-zA-Z0-9]{32})/", $apiKey)) {
|
15 |
+
throw new Billy_Exception("Billy has encountered an invalid API key");
|
16 |
+
}
|
17 |
+
|
18 |
+
$this->request = new Billy_Request($apiKey, $apiVersion);
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Run a GET request on Billy API on a specific address and receive an array as return.
|
23 |
+
*
|
24 |
+
* @param string $address Sub-address to call, e.g. invoices or invoices/ID_NUMBER
|
25 |
+
*
|
26 |
+
* @return array Response from Billy API, e.g. invoice object
|
27 |
+
*/
|
28 |
+
public function get($address) {
|
29 |
+
return $this->request->call("GET", $address);
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Run a POST request on Billy API on a specific address with parameters and receive an array as return.
|
34 |
+
*
|
35 |
+
* @param string $address Sub-address to call, e.g. invoices or contacts
|
36 |
+
* @param array $params Parameters to be sent to Billy API on the specified address
|
37 |
+
*
|
38 |
+
* @return array Response from Billy API, e.g. id and success
|
39 |
+
*/
|
40 |
+
public function post($address, $params) {
|
41 |
+
return $this->request->call("POST", $address, $params);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Run a fake GET request.
|
46 |
+
*
|
47 |
+
* @param string $address Sub-address to call, e.g. invoices or invoices/ID_NUMBER
|
48 |
+
*
|
49 |
+
* @return array Response from Billy API, e.g. invoice object
|
50 |
+
*/
|
51 |
+
public function fakeGet($outputFile, $address) {
|
52 |
+
return $this->request->fakeCall($outputFile, "GET", $address);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Run a fake POST request.
|
57 |
+
*
|
58 |
+
* @param string $address Sub-address to call, e.g. invoices or contacts
|
59 |
+
* @param array $params Parameters to be sent to Billy API on the specified address
|
60 |
+
*
|
61 |
+
* @return array Response from Billy API, e.g. id and success
|
62 |
+
*/
|
63 |
+
public function fakePost($outputFile, $address, $params) {
|
64 |
+
return $this->request->fakeCall($outputFile, "POST", $address, $params);
|
65 |
+
}
|
66 |
+
|
67 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/Billy/Exception.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Billy_Exception extends Exception {
|
3 |
+
public function __construct($message = null, $help_url = null, $json_body = null) {
|
4 |
+
parent::__construct($message);
|
5 |
+
$this->help_url = $help_url;
|
6 |
+
$this->json_body = $json_body;
|
7 |
+
}
|
8 |
+
|
9 |
+
public function getHelpUrl() {
|
10 |
+
return $this->help_url;
|
11 |
+
}
|
12 |
+
|
13 |
+
public function getJsonBody() {
|
14 |
+
return $this->json_body;
|
15 |
+
}
|
16 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/Billy/Request.php
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Billy_Request {
|
3 |
+
|
4 |
+
private $apiKey;
|
5 |
+
private $apiVersion;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Construct a Billy Request with an API key and an API version.
|
9 |
+
*
|
10 |
+
* @param string $apiKey API key from Billy
|
11 |
+
* @param string $apiVersion API version from Billy
|
12 |
+
*/
|
13 |
+
public function __construct($apiKey, $apiVersion) {
|
14 |
+
$this->apiKey = $apiKey;
|
15 |
+
$this->apiVersion = $apiVersion;
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Run a custom request on Billy API on a specific address with possible parameters and receive a response array as
|
20 |
+
* return.
|
21 |
+
*
|
22 |
+
* @param string $method Either GET or POST
|
23 |
+
* @param string $address Sub-address to call, e.g. invoices or invoices/ID_NUMBER
|
24 |
+
* @param OPTIONAL array $params Parameters to be sent to Billy API on the specified address
|
25 |
+
*
|
26 |
+
* @return array Response from Billy API, e.g. id and success or invoice object
|
27 |
+
*/
|
28 |
+
public function call($method, $address, $params = null) {
|
29 |
+
$ch = curl_init();
|
30 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
31 |
+
// Authentication
|
32 |
+
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
33 |
+
curl_setopt($ch, CURLOPT_USERPWD, $this->apiKey . ":");
|
34 |
+
// Request method
|
35 |
+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
36 |
+
// POST parameters
|
37 |
+
if ($method == "POST" && $params != null) {
|
38 |
+
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
|
39 |
+
}
|
40 |
+
// URL including API version and sub-address
|
41 |
+
curl_setopt($ch, CURLOPT_URL, "https://api.billysbilling.dk/" . $this->apiVersion . "/" . $address);
|
42 |
+
$rawResponse = curl_exec($ch);
|
43 |
+
curl_close($ch);
|
44 |
+
|
45 |
+
// Return response array
|
46 |
+
return $this->interpretResponse($rawResponse);
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Run a fake custom request.
|
51 |
+
*
|
52 |
+
* @param string $method Either GET or POST
|
53 |
+
* @param string $address Sub-address to call, e.g. invoices or invoices/ID_NUMBER
|
54 |
+
* @param OPTIONAL array $params Parameters to be sent to Billy API on the specified address
|
55 |
+
*
|
56 |
+
* @return array Response from Billy API, e.g. id and success or invoice object
|
57 |
+
*/
|
58 |
+
public function fakeCall($outputFile, $method, $address, $params = null) {
|
59 |
+
$call = array(
|
60 |
+
"mode" => $method,
|
61 |
+
"address" => $address
|
62 |
+
);
|
63 |
+
if ($params) {
|
64 |
+
$call["params"] = $params;
|
65 |
+
}
|
66 |
+
|
67 |
+
$handle = fopen($outputFile, "a");
|
68 |
+
fwrite($handle, json_encode($call) . "\n");
|
69 |
+
fclose($handle);
|
70 |
+
|
71 |
+
$response = new StdClass();
|
72 |
+
if ($method == "POST") {
|
73 |
+
$response->id = "12345-ABCDEFGHIJKLMNOP";
|
74 |
+
$response->success = true;
|
75 |
+
} else {
|
76 |
+
$addressParts = explode("?", $address);
|
77 |
+
$type = $addressParts[0];
|
78 |
+
$response->$type = array();
|
79 |
+
}
|
80 |
+
return $response;
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Takes a raw JSON response and decodes it. If an error is met, throw an exception. Else return array.
|
85 |
+
*
|
86 |
+
* @param string $rawResponse JSON encoded array
|
87 |
+
*
|
88 |
+
* @return array Response from Billy API, e.g. id and success or invoice object
|
89 |
+
* @throws Billy_Exception Error, Help URL and response
|
90 |
+
*/
|
91 |
+
private function interpretResponse($rawResponse) {
|
92 |
+
$response = json_decode($rawResponse);
|
93 |
+
if (!$response->success) {
|
94 |
+
throw new Billy_Exception($response->error, $response->helpUrl, $rawResponse);
|
95 |
+
}
|
96 |
+
|
97 |
+
return $response;
|
98 |
+
}
|
99 |
+
|
100 |
+
}
|
app/code/community/BillysBilling/Invoicer/Model/billysbilling-php/bootstrap.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if (!function_exists("curl_init")) {
|
3 |
+
throw new Exception("Billy needs the CURL PHP extension.");
|
4 |
+
}
|
5 |
+
if (!function_exists("json_decode")) {
|
6 |
+
throw new Exception("Billy needs the JSON PHP extension.");
|
7 |
+
}
|
8 |
+
|
9 |
+
require(dirname(__FILE__) . "/Billy/Client.php");
|
10 |
+
require(dirname(__FILE__) . "/Billy/Exception.php");
|
11 |
+
require(dirname(__FILE__) . "/Billy/Request.php");
|
app/code/community/BillysBilling/Invoicer/etc/config.xml
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<config>
|
2 |
+
<modules>
|
3 |
+
<BillysBilling_Invoicer>
|
4 |
+
<version>1.0.0</version>
|
5 |
+
</BillysBilling_Invoicer>
|
6 |
+
</modules>
|
7 |
+
<global>
|
8 |
+
<events>
|
9 |
+
<sales_order_invoice_register>
|
10 |
+
<observers>
|
11 |
+
<billysbilling_save_invoice_on_success>
|
12 |
+
<class>BillysBilling_Invoicer_Model_Observer</class>
|
13 |
+
<method>saveInvoiceOnSuccess</method>
|
14 |
+
</billysbilling_save_invoice_on_success>
|
15 |
+
</observers>
|
16 |
+
</sales_order_invoice_register>
|
17 |
+
</events>
|
18 |
+
<models>
|
19 |
+
<billysbilling>
|
20 |
+
<class>BillysBilling_Invoicer_Model</class>
|
21 |
+
</billysbilling>
|
22 |
+
</models>
|
23 |
+
<helpers>
|
24 |
+
<billysbilling>
|
25 |
+
<class>BillysBilling_Invoicer_Helper</class>
|
26 |
+
</billysbilling>
|
27 |
+
</helpers>
|
28 |
+
</global>
|
29 |
+
<adminhtml>
|
30 |
+
<acl>
|
31 |
+
<resources>
|
32 |
+
<all>
|
33 |
+
<title>Allow Everything</title>
|
34 |
+
</all>
|
35 |
+
<admin>
|
36 |
+
<children>
|
37 |
+
<system>
|
38 |
+
<children>
|
39 |
+
<config>
|
40 |
+
<children>
|
41 |
+
<billy>
|
42 |
+
<title>Billy - All</title>
|
43 |
+
</billy>
|
44 |
+
</children>
|
45 |
+
</config>
|
46 |
+
</children>
|
47 |
+
</system>
|
48 |
+
</children>
|
49 |
+
</admin>
|
50 |
+
</resources>
|
51 |
+
</acl>
|
52 |
+
</adminhtml>
|
53 |
+
</config>
|
app/code/community/BillysBilling/Invoicer/etc/system.xml
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<config>
|
3 |
+
<sections>
|
4 |
+
<billy translate="label" module="billysbilling">
|
5 |
+
<label>Billy's Billing</label>
|
6 |
+
<tab>service</tab>
|
7 |
+
<frontend_type>text</frontend_type>
|
8 |
+
<sort_order>400</sort_order>
|
9 |
+
<show_in_default>1</show_in_default>
|
10 |
+
<show_in_website>1</show_in_website>
|
11 |
+
<show_in_store>1</show_in_store>
|
12 |
+
<groups>
|
13 |
+
<api translate="label">
|
14 |
+
<label>API Settings</label>
|
15 |
+
<frontend_type>text</frontend_type>
|
16 |
+
<sort_order>200</sort_order>
|
17 |
+
<show_in_default>1</show_in_default>
|
18 |
+
<show_in_website>0</show_in_website>
|
19 |
+
<show_in_store>0</show_in_store>
|
20 |
+
<fields>
|
21 |
+
<api_key translate="label">
|
22 |
+
<label>API key</label>
|
23 |
+
<frontend_type>text</frontend_type>
|
24 |
+
<comment>Create or get your API key in Billy's web interface under (Danish) Indstillinger -> Organisationsindstillinger -> API. You have to enter API key and Save Config before you can choose shipping product, sales account and VAT model below.</comment>
|
25 |
+
<sort_order>10</sort_order>
|
26 |
+
<show_in_default>1</show_in_default>
|
27 |
+
<show_in_website>0</show_in_website>
|
28 |
+
<show_in_store>0</show_in_store>
|
29 |
+
</api_key>
|
30 |
+
</fields>
|
31 |
+
</api>
|
32 |
+
<invoicer translate="label">
|
33 |
+
<label>Invoice Settings</label>
|
34 |
+
<frontend_type>text</frontend_type>
|
35 |
+
<sort_order>300</sort_order>
|
36 |
+
<show_in_default>1</show_in_default>
|
37 |
+
<show_in_website>0</show_in_website>
|
38 |
+
<show_in_store>0</show_in_store>
|
39 |
+
<fields>
|
40 |
+
<shipping_account translate="label">
|
41 |
+
<label>Shipping Product</label>
|
42 |
+
<frontend_type>select</frontend_type>
|
43 |
+
<source_model>BillysBilling_Invoicer_Model_Products</source_model>
|
44 |
+
<sort_order>10</sort_order>
|
45 |
+
<show_in_default>1</show_in_default>
|
46 |
+
<show_in_website>0</show_in_website>
|
47 |
+
<show_in_store>0</show_in_store>
|
48 |
+
</shipping_account>
|
49 |
+
<sales_account translate="label">
|
50 |
+
<label>Sales Account</label>
|
51 |
+
<frontend_type>select</frontend_type>
|
52 |
+
<source_model>BillysBilling_Invoicer_Model_Accounts</source_model>
|
53 |
+
<sort_order>20</sort_order>
|
54 |
+
<show_in_default>1</show_in_default>
|
55 |
+
<show_in_website>0</show_in_website>
|
56 |
+
<show_in_store>0</show_in_store>
|
57 |
+
</sales_account>
|
58 |
+
<vat_model translate="label">
|
59 |
+
<label>VAT Model</label>
|
60 |
+
<frontend_type>select</frontend_type>
|
61 |
+
<source_model>BillysBilling_Invoicer_Model_VatModels</source_model>
|
62 |
+
<sort_order>30</sort_order>
|
63 |
+
<show_in_default>1</show_in_default>
|
64 |
+
<show_in_website>0</show_in_website>
|
65 |
+
<show_in_store>0</show_in_store>
|
66 |
+
</vat_model>
|
67 |
+
</fields>
|
68 |
+
</invoicer>
|
69 |
+
</groups>
|
70 |
+
</billy>
|
71 |
+
</sections>
|
72 |
+
</config>
|
app/etc/modules/BillysBilling_Invoicer.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<config>
|
2 |
+
<modules>
|
3 |
+
<BillysBilling_Invoicer>
|
4 |
+
<active>true</active>
|
5 |
+
<codePool>community</codePool>
|
6 |
+
</BillysBilling_Invoicer>
|
7 |
+
</modules>
|
8 |
+
</config>
|
package.xml
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>Billys_Billing_Invoicer</name>
|
4 |
+
<version>1.0.0</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Billy's Billing Invoicer for Magento enables you to automatically submit invoices to Billy's Billing.</summary>
|
10 |
+
<description>Billy's Billing Invoicer for Magento uses Billy's Billing's API to submit invoices to Billy's Billing automatically from orders created in the Magento shop. When orders are invoiced in Magento, they are automatically send to Billy's Billing with:
|
11 |
+
- General information about the order,
|
12 |
+
- Information about the customer, and
|
13 |
+
- Information about each product including shipping.
|
14 |
+

|
15 |
+
This extension has been testing with the latest releases of version 1.5, 1.6 and 1.7.
|
16 |
+

|
17 |
+
When this extension has been installed, you should go to System Configuration and access the Billy's Billing configuration page. From here you enter an API key (you can get this from organization settings in Billy's Billing) and save the configuration. When this is done, you will be able to change the dropdown boxes for shipping product, sales account and VAT model. After they have been selected, you are ready to use the extension.</description>
|
18 |
+
<notes>First stable release.</notes>
|
19 |
+
<authors><author><name>Billy's Billing</name><user>billysbilling</user><email>michael@billysbilling.com</email></author></authors>
|
20 |
+
<date>2013-03-21</date>
|
21 |
+
<time>12:10:53</time>
|
22 |
+
<contents><target name="magecommunity"><dir name="BillysBilling"><dir name="Invoicer"><dir name="Helper"><file name="Data.php" hash="2e73f30c86e3cb150b91856d2efeebf4"/></dir><dir name="Model"><file name="Accounts.php" hash="a6861ea516d74d199d52be6e4a8eeb1c"/><file name="Observer.php" hash="63da9b1b6c03202ecc2b3f0abe9496b9"/><file name="Products.php" hash="86953a3321a191587b6da1ab57626c53"/><file name="VatModels.php" hash="e87151fe22f857340476d1d4ebaeb31c"/><dir name="billysbilling-php"><dir name="Billy"><file name="Client.php" hash="b947948ae0063e2a121751782f44c751"/><file name="Exception.php" hash="239b2ecc8821b6e55faef561d0f3089c"/><file name="Request.php" hash="60d6c8d0661ff97cfc828cc785e7c942"/></dir><file name="bootstrap.php" hash="95d828828c4fdf4d338407f4a270c397"/><file name=".DS_Store" hash="ac8ffff9277a5c8cfaa12d9a1e52ef3e"/></dir><file name=".DS_Store" hash="e78a22cf29e6201ef29c5f0981c55604"/></dir><dir name="etc"><file name="config.xml" hash="1bbf2701ae5cd06789f24499b2ff65e7"/><file name="system.xml" hash="5bf923d3297151b518e5e484c9e36f2f"/></dir><file name=".DS_Store" hash="3fad5b10a22595598493fd98e0879784"/></dir><file name=".DS_Store" hash="099e78847f139a18fba02cd92135dd9a"/></dir></target><target name="mageetc"><dir name="modules"><file name="BillysBilling_Invoicer.xml" hash="4b11b30f403a358332323f04da27d1d4"/></dir></target></contents>
|
23 |
+
<compatible/>
|
24 |
+
<dependencies><required><php><min>5.3.0</min><max>5.4.4</max></php></required></dependencies>
|
25 |
+
</package>
|