Auctane_ShipStation - Version 1.3.6

Version Notes

Official release.
Capable of creating invoices and capturing payments when instructed to by ShipStation.

Download this release

Release Info

Developer Clockworkgeek
Extension Auctane_ShipStation
Version 1.3.6
Comparing to
See all releases


Code changes from version 1.3.4 to 1.3.6

app/code/community/Auctane/Api/Helper/Data.php CHANGED
@@ -79,4 +79,15 @@ class Auctane_Api_Helper_Data extends Mage_Core_Helper_Data
79
  return isset($types[$type]);
80
  }
81
 
 
 
 
 
 
 
 
 
 
 
 
82
  }
79
  return isset($types[$type]);
80
  }
81
 
82
+ /**
83
+ * A simple list of module names for debugging.
84
+ *
85
+ * @return string
86
+ */
87
+ public function getModuleList()
88
+ {
89
+ $modules = array_keys((array)Mage::getConfig()->getNode('modules')->children());
90
+ return implode(',', $modules);
91
+ }
92
+
93
  }
app/code/community/Auctane/Api/Model/Action/Export.php ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Auctane_Api_Model_Action_Export {
4
+
5
+ /**
6
+ * Perform an export according to the given request.
7
+ *
8
+ * @param Mage_Core_Controller_Request_Http $request
9
+ * @param Mage_Core_Controller_Response_Http $response
10
+ * @throws Exception
11
+ */
12
+ public function process(Mage_Core_Controller_Request_Http $request,
13
+ Mage_Core_Controller_Response_Http $response)
14
+ {
15
+ // In case store is part of URL path use it to choose config.
16
+ $store = $request->get('store');
17
+ if ($store) $store = Mage::app()->getStore($store);
18
+
19
+ $apiConfigCharset = Mage::getStoreConfig("api/config/charset", $store);
20
+
21
+ $start_date = strtotime($request->getParam('start_date'));
22
+ $end_date = strtotime($request->getParam('end_date'));
23
+ if (!$start_date || !$end_date) throw new Exception('Start and end dates are required', 400);
24
+
25
+ $page = (int) $request->getParam('page');
26
+
27
+ /* @var $orders Mage_Sales_Model_Mysql4_Order_Collection */
28
+ $orders = Mage::getResourceModel('sales/order_collection');
29
+ // might use 'created_at' attribute instead
30
+ $orders->addAttributeToFilter('updated_at',
31
+ array(
32
+ 'from' => date('Y-m-d H:i:s', $start_date),
33
+ 'to' => date('Y-m-d H:i:s', $end_date)
34
+ ));
35
+ if ($store) $orders->addAttributeToFilter('store_id', $store->getId());
36
+ if ($page > 0) $orders->setPage($page, $this->_getExportPageSize());
37
+
38
+ $xml = new XMLWriter;
39
+ $xml->openMemory();
40
+ $xml->startDocument('1.0', $apiConfigCharset);
41
+ $this->_writeOrders($orders, $xml, $store ? $store->getId() : 0);
42
+ $xml->endDocument();
43
+
44
+ $response->clearHeaders()
45
+ ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset)
46
+ ->setBody($xml->outputMemory(true));
47
+ }
48
+
49
+ protected function _getExportPageSize()
50
+ {
51
+ return (int) Mage::getStoreConfig('auctaneapi/config/exportPageSize');
52
+ }
53
+
54
+ protected function _writeOrders(Varien_Data_Collection $orders, XMLWriter $xml, $storeId = null)
55
+ {
56
+ $xml->startElement('Orders');
57
+ $xml->writeAttribute('pages', $orders->getLastPageNumber());
58
+ foreach ($orders as $order) {
59
+ $this->_writeOrder($order, $xml, $storeId);
60
+ }
61
+ $xml->startElement('Query');
62
+ $xml->writeCdata($orders->getSelectSql());
63
+ $xml->endElement(); // Query
64
+
65
+ $xml->startElement('Version');
66
+ $xml->writeCdata('Magento ' . Mage::getVersion());
67
+ $xml->endElement(); // Version
68
+
69
+ $xml->startElement('Extensions');
70
+ $xml->writeCdata(Mage::helper('auctaneapi')->getModuleList());
71
+ $xml->endElement(); // Extensions
72
+
73
+ $xml->endElement(); // Orders
74
+ }
75
+
76
+ protected function _writeOrder(Mage_Sales_Model_Order $order, XMLWriter $xml, $storeId = null)
77
+ {
78
+ $history = '';
79
+ /* @var $status Mage_Sales_Model_Order_Status */
80
+ foreach ($order->getStatusHistoryCollection() as $status) {
81
+ if ($status->getComment()) {
82
+ $history .= $status->getCreatedAt() . PHP_EOL;
83
+ $history .= $status->getComment() . PHP_EOL . PHP_EOL;
84
+ }
85
+ }
86
+ $history = trim($history);
87
+ if ($history) {
88
+ $order->setStatusHistoryText($history);
89
+ }
90
+
91
+ /* @var $gift Mage_GiftMessage_Model_Message */
92
+ $gift = Mage::helper('giftmessage/message')->getGiftMessage($order->getGiftMessageId());
93
+ $order->setGift($gift->isObjectNew() ? 'false' : 'true');
94
+ if (!$gift->isObjectNew()) {
95
+ $order->setGiftMessage(sprintf("From: %s\nTo: %s\nMessage: %s",
96
+ $gift->getSender(), $gift->getRecipient(), $gift->getMessage()));
97
+ }
98
+
99
+ $helper = Mage::helper('auctaneapi');
100
+
101
+ $xml->startElement('Order');
102
+ $helper->fieldsetToXml('sales_order', $order, $xml);
103
+
104
+ $xml->startElement('Customer');
105
+ $xml->startElement('CustomerCode');
106
+ $xml->writeCdata($order->getCustomerEmail());
107
+ $xml->endElement(); // CustomerCode
108
+
109
+ $xml->startElement('BillTo');
110
+ $helper->fieldsetToXml('sales_order_billing_address',
111
+ $order->getBillingAddress(), $xml);
112
+ $xml->endElement(); // BillTo
113
+
114
+ $xml->startElement('ShipTo');
115
+ $helper->fieldsetToXml('sales_order_shipping_address',
116
+ $order->getShippingAddress(), $xml);
117
+ $xml->endElement(); // ShipTo
118
+
119
+ $xml->endElement(); // Customer
120
+
121
+ $xml->startElement('Items');
122
+ /* @var $item Mage_Sales_Model_Order_Item */
123
+ foreach ($order->getItemsCollection($helper->getIncludedProductTypes()) as $item) {
124
+ $this->_writeOrderItem($item, $xml, $storeId);
125
+ }
126
+ $xml->endElement(); // Items
127
+
128
+ $xml->endElement(); // Order
129
+ }
130
+
131
+ protected function _writeOrderItem(Mage_Sales_Model_Order_Item $item, XMLWriter $xml, $storeId = null)
132
+ {
133
+ // inherit some attributes from parent order item
134
+ if ($item->getParentItemId() && !$item->getParentItem()) {
135
+ $item->setParentItem(Mage::getModel('sales/order_item')->load($item->getParentItemId()));
136
+ }
137
+ // only inherit if parent has been hidden
138
+ if ($item->getParentItem() && ($item->getPrice() == 0.000)
139
+ && (Mage::helper('auctaneapi')->isExcludedProductType($item->getParentItem()->getProductType())))
140
+ {
141
+ $item->setPrice($item->getParentItem()->getPrice());
142
+ }
143
+
144
+ /* @var $gift Mage_GiftMessage_Model_Message */
145
+ $gift = Mage::helper('giftmessage/message')->getGiftMessage(
146
+ !$item->getGiftMessageId() && $item->getParentItem()
147
+ ? $item->getParentItem()->getGiftMessageId()
148
+ : $item->getGiftMessageId());
149
+ $item->setGift($gift->isObjectNew() ? 'false' : 'true');
150
+ if (!$gift->isObjectNew()) {
151
+ $item->setGiftMessage(sprintf("From: %s\nTo: %s\nMessage: %s",
152
+ $gift->getSender(), $gift->getRecipient(), $gift->getMessage()));
153
+ }
154
+
155
+ /* @var $product Mage_Catalog_Model_Product */
156
+ $product = Mage::getModel('catalog/product')
157
+ ->setStoreId($storeId)
158
+ ->load($item->getProductId());
159
+ // inherit some attributes from parent product item
160
+ if (($parentProduct = $this->_getOrderItemParentProduct($item, $storeId))) {
161
+ if (!$product->getImage() || ($product->getImage() == 'no_selection'))
162
+ $product->setImage($parentProduct->getImage());
163
+ if (!$product->getSmallImage() || ($product->getSmallImage() == 'no_selection'))
164
+ $product->setSmallImage($parentProduct->getSmallImage());
165
+ if (!$product->getThumbnail() || ($product->getThumbnail() == 'no_selection'))
166
+ $product->setThumbnail($parentProduct->getThumbnail());
167
+ }
168
+
169
+ $xml->startElement('Item');
170
+ Mage::helper('auctaneapi')->fieldsetToXml('sales_order_item', $item, $xml);
171
+ Mage::helper('auctaneapi')->fieldsetToXml('sales_order_item_product',
172
+ $product, $xml);
173
+
174
+ $xml->startElement('Options');
175
+ $this->_writeOrderProductAttribute($product, $xml, $storeId);
176
+ // items may have several custom options chosen by customer
177
+ foreach ((array) $item->getProductOptionByCode('options') as $option) {
178
+ $this->_writeOrderItemOption($option, $xml, $storeId);
179
+ }
180
+ $buyRequest = $item->getProductOptionByCode('info_buyRequest');
181
+ if ($buyRequest && @$buyRequest['super_attribute']) {
182
+ // super_attribute is non-null and non-empty, there must be a Configurable involved
183
+ $parentItem = $this->_getOrderItemParent($item);
184
+ foreach ((array) $parentItem->getProductOptionByCode('attributes_info') as $option) {
185
+ $this->_writeOrderItemOption($option, $xml, $storeId);
186
+ }
187
+ }
188
+ $xml->endElement(); // Options
189
+
190
+ $xml->endElement(); // Item
191
+ }
192
+
193
+ protected function _writeOrderProductAttribute(Mage_Catalog_Model_Product $product, XMLWriter $xml, $storeId = null)
194
+ {
195
+ // custom attributes are specified in Admin > Configuration > Sales > Auctane Shipstation API
196
+ // static because attributes can be cached, they do not change during a request
197
+ static $attrs = null;
198
+ if (is_null($attrs)) {
199
+ $attrs = Mage::getResourceModel('eav/entity_attribute_collection');
200
+ $attrIds = explode(',', Mage::getStoreConfig('sales/auctaneapi/customattributes', $storeId));
201
+ $attrs->addFieldToFilter('attribute_id', $attrIds);
202
+ }
203
+
204
+ /* @var $attr Mage_Eav_Model_Entity_Attribute */
205
+ foreach ($attrs as $attr) {
206
+ if ($product->hasData($attr->getName())) {
207
+ // if an attribute has options/labels
208
+ if (in_array($attr->getFrontendInput(), array('select', 'multiselect'))) {
209
+ $value = $product->getAttributeText($attr->getName());
210
+ if (is_array($value)) $value = implode(',', $value);
211
+ }
212
+ // else is a static value
213
+ else {
214
+ $value = $product->getDataUsingMethod($attr->getName());
215
+ }
216
+ // fake an item option
217
+ $option = array(
218
+ 'value' => $value,
219
+ 'label' => $attr->getFrontendLabel()
220
+ );
221
+ $this->_writeOrderItemOption($option, $xml, $storeId);
222
+ }
223
+ }
224
+ }
225
+
226
+ protected function _writeOrderItemOption($option, XMLWriter $xml)
227
+ {
228
+ $xml->startElement('Option');
229
+ Mage::helper('auctaneapi')->fieldsetToXml('sales_order_item_option', $option, $xml);
230
+ $xml->endElement(); // Option
231
+ }
232
+
233
+ /**
234
+ * Safe way to lookup parent order items.
235
+ *
236
+ * @param Mage_Sales_Model_Order_Item $item
237
+ * @return Mage_Sales_Model_Order_Item
238
+ */
239
+ protected function _getOrderItemParent(Mage_Sales_Model_Order_Item $item)
240
+ {
241
+ if ($item->getParentItem()) {
242
+ return $item->getParentItem();
243
+ }
244
+
245
+ $parentItem = Mage::getModel('sales/order_item')
246
+ ->load($item->getParentItemId());
247
+ $item->setParentItem($parentItem);
248
+ return $parentItem;
249
+ }
250
+
251
+ /**
252
+ * @param Mage_Sales_Model_Order_Item $item
253
+ * @param mixed $storeId
254
+ * @return Mage_Catalog_Model_Product
255
+ */
256
+ protected function _getOrderItemParentProduct(Mage_Sales_Model_Order_Item $item, $storeId = null)
257
+ {
258
+ if ($item->getParentItemId()) {
259
+ // cannot use getParentItem() because we stripped parents from the order
260
+ $parentItem = $this->_getOrderItemParent($item);
261
+ // initialise with store so that images are correct
262
+ return Mage::getModel('catalog/product')
263
+ ->setStoreId($storeId)
264
+ ->load($parentItem->getProductId());
265
+ }
266
+ return null;
267
+ }
268
+
269
+ }
app/code/community/Auctane/Api/Model/Action/Shipnotify.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Auctane_Api_Model_Action_Shipnotify {
4
+
5
+ /**
6
+ * Perform a notify using POSTed data.
7
+ *
8
+ * See Auctane API specification.
9
+ *
10
+ * @param Mage_Core_Controller_Request_Http $request
11
+ * @throws Exception
12
+ */
13
+ public function process(Mage_Core_Controller_Request_Http $request)
14
+ {
15
+ // Raw XML is POSTed to this stream
16
+ $xml = simplexml_load_file('php://input');
17
+
18
+ // load some objects
19
+ $order = $this->_getOrder($xml->OrderNumber);
20
+ $carrier = $this->_getCarrier(@$xml->Carrier);
21
+ $qtys = $this->_getOrderItemQtys(@$xml->Items, $order);
22
+ $shipment = $this->_getOrderShipment($order, $qtys);
23
+
24
+ // this is where tracking is actually added
25
+ $track = Mage::getModel('sales/order_shipment_track')
26
+ ->setNumber($xml->TrackingNumber)
27
+ ->setCarrierCode($xml->Carrier)
28
+ ->setTitle($xml->Service);
29
+ $shipment->addTrack($track);
30
+
31
+ // 'NotifyCustomer' must be "true" or "yes" to trigger an email
32
+ $notify = filter_var(@$xml->NotifyCustomer, FILTER_VALIDATE_BOOLEAN);
33
+
34
+ $capture = filter_var($request->getParam('capture'), FILTER_VALIDATE_BOOLEAN);
35
+ if ($capture && $order->canInvoice()) {
36
+ $invoice = $order->prepareInvoice($qtys);
37
+ $invoice->register(); // captures & updates order totals
38
+ $invoice->addComment($this->_getInvoiceComment(), $notify)
39
+ ->sendEmail($notify); // always send to store manager, and optionally notify customer too
40
+ $order->setIsInProcess(true); // updates status on save
41
+ }
42
+
43
+ // Internal notes are only visible to admin
44
+ if (@$xml->InternalNotes) {
45
+ $shipment->addComment($xml->InternalNotes);
46
+ }
47
+ // Customer notes have 'Visible On Frontend' set
48
+ if (@$xml->NotesToCustomer) {
49
+ if ($notify) {
50
+ $shipment
51
+ ->sendEmail(true, $xml->NotesToCustomer)
52
+ ->setEmailSent(true);
53
+ }
54
+ $shipment->addComment($xml->NotesToCustomer, $notify, true);
55
+ }
56
+
57
+ $transaction = Mage::getModel('core/resource_transaction');
58
+ $transaction->addObject($shipment)
59
+ ->addObject($track);
60
+ if (isset($invoice)) {
61
+ // order has been captured, therefore has been modified
62
+ $transaction->addObject($invoice)
63
+ ->addObject($order);
64
+ }
65
+ $transaction->save();
66
+ }
67
+
68
+ /**
69
+ * Configurable comment, in case language needs to be changed.
70
+ *
71
+ * @return string
72
+ */
73
+ protected function _getInvoiceComment()
74
+ {
75
+ return Mage::getStoreConfig('auctaneapi/config/invoiceComment');
76
+ }
77
+
78
+ /**
79
+ * @param string $carrierCode
80
+ * @return Mage_Shipping_Model_Carrier_Interface
81
+ */
82
+ protected function _getCarrier($carrierCode)
83
+ {
84
+ $carrierCode = strtolower($carrierCode);
85
+ $carrierModel = Mage::getStoreConfig("carriers/{$carrierCode}/model");
86
+ if (!$carrierModel) throw new Exception('Invalid carrier specified.', 400);
87
+ /* @var $carrier Mage_Shipping_Model_Carrier_Interface */
88
+ $carrier = Mage::getModel($carrierModel);
89
+ if (!$carrier) throw new Exception('Invalid carrier specified.', 400);
90
+ if (!$carrier->isTrackingAvailable()) throw new Exception('Carrier does not supported tracking.', 400);
91
+ return $carrier;
92
+ }
93
+
94
+ /**
95
+ * @param string $orderIncrementId
96
+ * @return Mage_Sales_Model_Order
97
+ */
98
+ protected function _getOrder($orderIncrementId)
99
+ {
100
+ $order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);
101
+ if ($order->isObjectNew()) throw new Exception("Order '{$orderIncrementId}' does not exist", 400);
102
+ return $order;
103
+ }
104
+
105
+ protected function _getOrderItemQtys(SimpleXMLElement $xmlItems, Mage_Sales_Model_Order $order)
106
+ {
107
+ /* @var $items Mage_Sales_Model_Mysql4_Order_Item_Collection */
108
+ $items = $order->getItemsCollection();
109
+ $qtys = array();
110
+ /* @var $item Mage_Sales_Model_Order_Item */
111
+ foreach ($items as $item) {
112
+ // search for item by SKU
113
+ @list($xmlItem) = $xmlItems->xpath(sprintf('//Item/SKU[text()="%s"]/..',
114
+ addslashes($item->getSku())));
115
+ if ($xmlItem) {
116
+ // store quantity by order item ID, not by SKU
117
+ $qtys[$item->getId()] = (float) $xmlItem->Quantity;
118
+ }
119
+ }
120
+ return $qtys;
121
+ }
122
+
123
+ /**
124
+ * @param Mage_Sales_ModelOrder $order
125
+ * @param array $qtys
126
+ * @return Mage_Sales_Model_Order_Shipment
127
+ */
128
+ protected function _getOrderShipment(Mage_Sales_Model_Order $order, $qtys)
129
+ {
130
+ /* @var $shipments Mage_Sales_Model_Mysql4_Order_Shipment_Collection */
131
+ $shipments = $order->getShipmentsCollection();
132
+ /* @var $shipment Mage_Sales_Model_Order_Shipment */
133
+ if (($shipments === false) || ($shipments->count() === 0)) {
134
+ // order has no shipments yet, create one
135
+ $shipment = $order->prepareShipment($qtys);
136
+ $shipment->register();
137
+ $order->setIsInProgress(true);
138
+ // shipment must have an ID before proceeding
139
+ Mage::getModel('core/resource_transaction')
140
+ ->addObject($shipment)
141
+ ->addObject($order)
142
+ ->save();
143
+ }
144
+ else {
145
+ // probably only one shipment for all items, assume the last is most recent
146
+ $shipment = $shipments->getLastItem();
147
+ }
148
+ return $shipment;
149
+ }
150
+
151
+ }
app/code/community/Auctane/Api/Model/Server/Adapter.php CHANGED
@@ -66,17 +66,6 @@ class Auctane_Api_Model_Server_Adapter
66
  return $this->getData('controller');
67
  }
68
 
69
- protected function _getExportPageSize()
70
- {
71
- return (int) Mage::getStoreConfig('auctaneapi/config/exportPageSize');
72
- }
73
-
74
- protected function _getModuleList()
75
- {
76
- $modules = array_keys((array)Mage::getConfig()->getNode('modules')->children());
77
- return implode(',', $modules);
78
- }
79
-
80
  /**
81
  * Run webservice
82
  *
@@ -95,79 +84,15 @@ class Auctane_Api_Model_Server_Adapter
95
  $this->fault(401, 'Unauthorized');
96
  }
97
 
98
- // In case store is part of URL path use it to choose config.
99
- $store = $this->getController()->getRequest()->get('store');
100
- if ($store) $store = Mage::app()->getStore($store);
101
-
102
- $apiConfigCharset = Mage::getStoreConfig("api/config/charset", $store);
103
-
104
  try { switch ($this->getController()->getRequest()->getParam('action', 'export')) {
105
  case 'export':
106
- $start_date = strtotime($this->getController()->getRequest()->getParam('start_date'));
107
- $end_date = strtotime($this->getController()->getRequest()->getParam('end_date'));
108
- if (!$start_date || !$end_date) throw new Exception('Start and end dates are required', 400);
109
-
110
- $page = (int) $this->getController()->getRequest()->getParam('page');
111
-
112
- /* @var $orders Mage_Sales_Model_Mysql4_Order_Collection */
113
- $orders = Mage::getResourceModel('sales/order_collection');
114
- // might use 'created_at' attribute instead
115
- $orders->addAttributeToFilter('updated_at',
116
- array(
117
- 'from' => date('Y-m-d H:i:s', $start_date),
118
- 'to' => date('Y-m-d H:i:s', $end_date)
119
- ));
120
- if ($store) $orders->addAttributeToFilter('store_id', $store->getId());
121
- if ($page > 0) $orders->setPage($page, $this->_getExportPageSize());
122
-
123
- $xml = new XMLWriter;
124
- $xml->openMemory();
125
- $xml->startDocument('1.0', $apiConfigCharset);
126
- $this->_writeOrders($orders, $xml, $store ? $store->getId() : 0);
127
- $xml->endDocument();
128
-
129
- $this->getController()->getResponse()
130
- ->clearHeaders()
131
- ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset)
132
- ->setBody($xml->outputMemory(true));
133
  break;
134
  case 'shipnotify':
135
- // Raw XML is POSTed to this stream
136
- $xml = simplexml_load_file('php://input');
137
-
138
- // load some objects
139
- $order = $this->_getOrder($xml->OrderNumber);
140
- $carrier = $this->_getCarrier(@$xml->Carrier);
141
- $qtys = $this->_getOrderItemQtys(@$xml->Items, $order);
142
- $shipment = $this->_getOrderShipment($order, $qtys);
143
-
144
- // this is where tracking is actually added
145
- $track = Mage::getModel('sales/order_shipment_track')
146
- ->setNumber($xml->TrackingNumber)
147
- ->setCarrierCode($xml->Carrier)
148
- ->setTitle($xml->Service);
149
- $shipment->addTrack($track);
150
-
151
- // Internal notes are only visible to admin
152
- if (@$xml->InternalNotes) {
153
- $shipment->addComment($xml->InternalNotes);
154
- }
155
- // Customer notes have 'Visible On Frontend' set
156
- // 'NotifyCustomer' must be "true" or "yes" to trigger an email
157
- if (@$xml->NotesToCustomer) {
158
- $notify = filter_var(@$xml->NotifyCustomer, FILTER_VALIDATE_BOOLEAN);
159
- if ($notify) {
160
- $shipment
161
- ->sendEmail(true, $xml->NotesToCustomer)
162
- ->setEmailSent(true);
163
- }
164
- $shipment->addComment($xml->NotesToCustomer, $notify, true);
165
- }
166
-
167
- Mage::getModel('core/resource_transaction')
168
- ->addObject($shipment)
169
- ->addObject($track)
170
- ->save();
171
  // if there hasn't been an error yet the work is done and a "200 OK" is given
172
  break;
173
  }}
@@ -198,267 +123,4 @@ class Auctane_Api_Model_Server_Adapter
198
  ');
199
  }
200
 
201
- protected function _writeOrders(Varien_Data_Collection $orders, XMLWriter $xml, $storeId = null)
202
- {
203
- $xml->startElement('Orders');
204
- $xml->writeAttribute('pages', $orders->getLastPageNumber());
205
- foreach ($orders as $order) {
206
- $this->_writeOrder($order, $xml, $storeId);
207
- }
208
- $xml->startElement('Query');
209
- $xml->writeCdata($orders->getSelectSql());
210
- $xml->endElement(); // Query
211
-
212
- $xml->startElement('Version');
213
- $xml->writeCdata('Magento ' . Mage::getVersion());
214
- $xml->endElement(); // Version
215
-
216
- $xml->startElement('Extensions');
217
- $xml->writeCdata($this->_getModuleList());
218
- $xml->endElement(); // Extensions
219
-
220
- $xml->endElement(); // Orders
221
- }
222
-
223
- protected function _writeOrder(Mage_Sales_Model_Order $order, XMLWriter $xml, $storeId = null)
224
- {
225
- $history = '';
226
- /* @var $status Mage_Sales_Model_Order_Status */
227
- foreach ($order->getStatusHistoryCollection() as $status) {
228
- if ($status->getComment()) {
229
- $history .= $status->getCreatedAt() . PHP_EOL;
230
- $history .= $status->getComment() . PHP_EOL . PHP_EOL;
231
- }
232
- }
233
- $history = trim($history);
234
- if ($history) {
235
- $order->setStatusHistoryText($history);
236
- }
237
-
238
- /* @var $gift Mage_GiftMessage_Model_Message */
239
- $gift = Mage::helper('giftmessage/message')->getGiftMessage($order->getGiftMessageId());
240
- $order->setGift($gift->isObjectNew() ? 'false' : 'true');
241
- if (!$gift->isObjectNew()) {
242
- $order->setGiftMessage(sprintf("From: %s\nTo: %s\nMessage: %s",
243
- $gift->getSender(), $gift->getRecipient(), $gift->getMessage()));
244
- }
245
-
246
- $helper = Mage::helper('auctaneapi');
247
-
248
- $xml->startElement('Order');
249
- $helper->fieldsetToXml('sales_order', $order, $xml);
250
-
251
- $xml->startElement('Customer');
252
- $xml->startElement('CustomerCode');
253
- $xml->writeCdata($order->getCustomerEmail());
254
- $xml->endElement(); // CustomerCode
255
-
256
- $xml->startElement('BillTo');
257
- $helper->fieldsetToXml('sales_order_billing_address',
258
- $order->getBillingAddress(), $xml);
259
- $xml->endElement(); // BillTo
260
-
261
- $xml->startElement('ShipTo');
262
- $helper->fieldsetToXml('sales_order_shipping_address',
263
- $order->getShippingAddress(), $xml);
264
- $xml->endElement(); // ShipTo
265
-
266
- $xml->endElement(); // Customer
267
-
268
- $xml->startElement('Items');
269
- /* @var $item Mage_Sales_Model_Order_Item */
270
- foreach ($order->getItemsCollection($helper->getIncludedProductTypes()) as $item) {
271
- $this->_writeOrderItem($item, $xml, $storeId);
272
- }
273
- $xml->endElement(); // Items
274
-
275
- $xml->endElement(); // Order
276
- }
277
-
278
- protected function _writeOrderItem(Mage_Sales_Model_Order_Item $item, XMLWriter $xml, $storeId = null)
279
- {
280
- // inherit some attributes from parent order item
281
- if ($item->getParentItemId() && !$item->getParentItem()) {
282
- $item->setParentItem(Mage::getModel('sales/order_item')->load($item->getParentItemId()));
283
- }
284
- // only inherit if parent has been hidden
285
- if ($item->getParentItem() && ($item->getPrice() == 0.000)
286
- && (Mage::helper('auctaneapi')->isExcludedProductType($item->getParentItem()->getProductType())))
287
- {
288
- $item->setPrice($item->getParentItem()->getPrice());
289
- }
290
-
291
- /* @var $gift Mage_GiftMessage_Model_Message */
292
- $gift = Mage::helper('giftmessage/message')->getGiftMessage(
293
- !$item->getGiftMessageId() && $item->getParentItem()
294
- ? $item->getParentItem()->getGiftMessageId()
295
- : $item->getGiftMessageId());
296
- $item->setGift($gift->isObjectNew() ? 'false' : 'true');
297
- if (!$gift->isObjectNew()) {
298
- $item->setGiftMessage(sprintf("From: %s\nTo: %s\nMessage: %s",
299
- $gift->getSender(), $gift->getRecipient(), $gift->getMessage()));
300
- }
301
-
302
- /* @var $product Mage_Catalog_Model_Product */
303
- $product = Mage::getModel('catalog/product')
304
- ->setStoreId($storeId)
305
- ->load($item->getProductId());
306
- // inherit some attributes from parent product item
307
- if (($parentProduct = $this->_getOrderItemParentProduct($item, $storeId))) {
308
- if (!$product->getImage() || ($product->getImage() == 'no_selection'))
309
- $product->setImage($parentProduct->getImage());
310
- if (!$product->getSmallImage() || ($product->getSmallImage() == 'no_selection'))
311
- $product->setSmallImage($parentProduct->getSmallImage());
312
- if (!$product->getThumbnail() || ($product->getThumbnail() == 'no_selection'))
313
- $product->setThumbnail($parentProduct->getThumbnail());
314
- }
315
-
316
- $xml->startElement('Item');
317
- Mage::helper('auctaneapi')->fieldsetToXml('sales_order_item', $item, $xml);
318
- Mage::helper('auctaneapi')->fieldsetToXml('sales_order_item_product',
319
- $product, $xml);
320
-
321
- $xml->startElement('Options');
322
- $this->_writeOrderProductAttribute($product, $xml, $storeId);
323
- // items may have several custom options chosen by customer
324
- foreach ((array) $item->getProductOptionByCode('options') as $option) {
325
- $this->_writeOrderItemOption($option, $xml, $storeId);
326
- }
327
- $xml->endElement(); // Options
328
-
329
- $xml->endElement(); // Item
330
- }
331
-
332
- protected function _writeOrderProductAttribute(Mage_Catalog_Model_Product $product, XMLWriter $xml, $storeId = null)
333
- {
334
- // custom attributes are specified in Admin > Configuration > Sales > Auctane Shipstation API
335
- // static because attributes can be cached, they do not change during a request
336
- static $attrs = null;
337
- if (is_null($attrs)) {
338
- $attrs = Mage::getResourceModel('eav/entity_attribute_collection');
339
- $attrIds = explode(',', Mage::getStoreConfig('sales/auctaneapi/customattributes', $storeId));
340
- $attrs->addFieldToFilter('attribute_id', $attrIds);
341
- }
342
-
343
- /* @var $attr Mage_Eav_Model_Entity_Attribute */
344
- foreach ($attrs as $attr) {
345
- if ($product->hasData($attr->getName())) {
346
- // if an attribute has options/labels
347
- if (in_array($attr->getFrontendInput(), array('select', 'multiselect'))) {
348
- $value = $product->getAttributeText($attr->getName());
349
- if (is_array($value)) $value = implode(',', $value);
350
- }
351
- // else is a static value
352
- else {
353
- $value = $product->getDataUsingMethod($attr->getName());
354
- }
355
- // fake an item option
356
- $option = array(
357
- 'value' => $value,
358
- 'label' => $attr->getFrontendLabel()
359
- );
360
- $this->_writeOrderItemOption($option, $xml, $storeId);
361
- }
362
- }
363
- }
364
-
365
- protected function _writeOrderItemOption($option, XMLWriter $xml)
366
- {
367
- $xml->startElement('Option');
368
- Mage::helper('auctaneapi')->fieldsetToXml('sales_order_item_option', $option, $xml);
369
- $xml->endElement(); // Option
370
- }
371
-
372
- /**
373
- * @param string $carrierCode
374
- * @return Mage_Shipping_Model_Carrier_Interface
375
- */
376
- protected function _getCarrier($carrierCode)
377
- {
378
- $carrierCode = strtolower($carrierCode);
379
- $carrierModel = Mage::getStoreConfig("carriers/{$carrierCode}/model");
380
- if (!$carrierModel) throw new Exception('Invalid carrier specified.', 400);
381
- /* @var $carrier Mage_Shipping_Model_Carrier_Interface */
382
- $carrier = Mage::getModel($carrierModel);
383
- if (!$carrier) throw new Exception('Invalid carrier specified.', 400);
384
- if (!$carrier->isTrackingAvailable()) throw new Exception('Carrier does not supported tracking.', 400);
385
- return $carrier;
386
- }
387
-
388
- /**
389
- * @param string $orderIncrementId
390
- * @return Mage_Sales_Model_Order
391
- */
392
- protected function _getOrder($orderIncrementId)
393
- {
394
- $order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);
395
- if ($order->isObjectNew()) throw new Exception("Order '{$orderIncrementId}' does not exist", 400);
396
- return $order;
397
- }
398
-
399
- protected function _getOrderItemQtys(SimpleXMLElement $xmlItems, Mage_Sales_Model_Order $order)
400
- {
401
- /* @var $items Mage_Sales_Model_Mysql4_Order_Item_Collection */
402
- $items = $order->getItemsCollection();
403
- $qtys = array();
404
- /* @var $item Mage_Sales_Model_Order_Item */
405
- foreach ($items as $item) {
406
- // search for item by SKU
407
- @list($xmlItem) = $xmlItems->xpath(sprintf('//Item/SKU[text()="%s"]/..',
408
- addslashes($item->getSku())));
409
- if ($xmlItem) {
410
- // store quantity by order item ID, not by SKU
411
- $qtys[$item->getId()] = (float) $xmlItem->Quantity;
412
- }
413
- }
414
- return $qtys;
415
- }
416
-
417
- /**
418
- * @param Mage_Sales_Model_Order_Item $item
419
- * @param mixed $storeId
420
- * @return Mage_Catalog_Model_Product
421
- */
422
- protected function _getOrderItemParentProduct(Mage_Sales_Model_Order_Item $item, $storeId = null)
423
- {
424
- if ($item->getParentItemId()) {
425
- // cannot use getParentItem() because we stripped parents from the order
426
- $parentItem = Mage::getModel('sales/order_item')
427
- ->load($item->getParentItemId());
428
- // initialise with store so that images are correct
429
- return Mage::getModel('catalog/product')
430
- ->setStoreId($storeId)
431
- ->load($parentItem->getProductId());
432
- }
433
- return null;
434
- }
435
-
436
- /**
437
- * @param Mage_Sales_ModelOrder $order
438
- * @param array $qtys
439
- * @return Mage_Sales_Model_Order_Shipment
440
- */
441
- protected function _getOrderShipment(Mage_Sales_Model_Order $order, $qtys)
442
- {
443
- /* @var $shipments Mage_Sales_Model_Mysql4_Order_Shipment_Collection */
444
- $shipments = $order->getShipmentsCollection();
445
- /* @var $shipment Mage_Sales_Model_Order_Shipment */
446
- if (($shipments === false) || ($shipments->count() === 0)) {
447
- // order has no shipments yet, create one
448
- $shipment = $order->prepareShipment($qtys);
449
- $shipment->register();
450
- $order->setIsInProgress(true);
451
- // shipment must have an ID before proceeding
452
- Mage::getModel('core/resource_transaction')
453
- ->addObject($shipment)
454
- ->addObject($order)
455
- ->save();
456
- }
457
- else {
458
- // probably only one shipment for all items, assume the last is most recent
459
- $shipment = $shipments->getLastItem();
460
- }
461
- return $shipment;
462
- }
463
-
464
  }
66
  return $this->getData('controller');
67
  }
68
 
 
 
 
 
 
 
 
 
 
 
 
69
  /**
70
  * Run webservice
71
  *
84
  $this->fault(401, 'Unauthorized');
85
  }
86
 
 
 
 
 
 
 
87
  try { switch ($this->getController()->getRequest()->getParam('action', 'export')) {
88
  case 'export':
89
+ $action = Mage::getModel('auctaneapi/action_export');
90
+ $action->process($this->getController()->getRequest(),
91
+ $this->getController()->getResponse());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  break;
93
  case 'shipnotify':
94
+ $action = Mage::getModel('auctaneapi/action_shipnotify');
95
+ $action->process($this->getController()->getRequest());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  // if there hasn't been an error yet the work is done and a "200 OK" is given
97
  break;
98
  }}
123
  ');
124
  }
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
app/code/community/Auctane/Api/etc/config.xml CHANGED
@@ -19,7 +19,7 @@
19
  <config>
20
  <modules>
21
  <Auctane_Api>
22
- <version>0.3.1</version>
23
  </Auctane_Api>
24
  </modules>
25
 
@@ -154,6 +154,7 @@
154
  <config>
155
  <realm>Auctane ShipStation</realm>
156
  <exportPageSize>100</exportPageSize>
 
157
  </config>
158
  </auctaneapi>
159
  </default>
19
  <config>
20
  <modules>
21
  <Auctane_Api>
22
+ <version>0.6.0</version>
23
  </Auctane_Api>
24
  </modules>
25
 
154
  <config>
155
  <realm>Auctane ShipStation</realm>
156
  <exportPageSize>100</exportPageSize>
157
+ <invoiceComment>Issued by Auctane ShipStation.</invoiceComment>
158
  </config>
159
  </auctaneapi>
160
  </default>
app/code/community/Auctane/ShipStation/etc/config.xml CHANGED
@@ -19,7 +19,7 @@
19
  <config>
20
  <modules>
21
  <Auctane_ShipStation>
22
- <version>1.3.4</version>
23
  </Auctane_ShipStation>
24
  </modules>
25
 
19
  <config>
20
  <modules>
21
  <Auctane_ShipStation>
22
+ <version>1.3.6</version>
23
  </Auctane_ShipStation>
24
  </modules>
25
 
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Auctane_ShipStation</name>
4
- <version>1.3.4</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
  <channel>community</channel>
@@ -9,11 +9,11 @@
9
  <summary>ShipStation is a web-based shipping solution that is integrated with the Magento API for retrieving order information and updating shipping details.</summary>
10
  <description>ShipStation is a web-based shipping solution that is integrated with the Magento API for retrieving order information and updating shipping details.</description>
11
  <notes>Official release.&#xD;
12
- Wrap exported text fields in CDATA as a precaution.</notes>
13
  <authors><author><name>clockworkgeek</name><user>nonproffessional</user><email>nonproffessional@clockworkgeek.com</email></author></authors>
14
- <date>2013-04-17</date>
15
- <time>21:15:55</time>
16
- <contents><target name="magecommunity"><dir name="Auctane"><dir name="ShipStation"><dir name="Block"><dir name="Adminhtml"><dir name="Linkup"><file name="Form.php" hash="68b7c7bc627e89c304cf630c24aa5164"/></dir><file name="Linkup.php" hash="f280d1f6a26e74244898ea16cdf29c9b"/><file name="Pending.php" hash="6bc7a07b5d0b5192db32fefc55b94b08"/></dir></dir><dir name="Helper"><file name="Data.php" hash="cf2bd6a04dd7b88cae8096c2dd548214"/></dir><file name="LICENSE.html" hash="caf0a79ffb5e4719f9f4de286f253a61"/><file name="LICENSE.txt" hash="59563e7be45096d0833dade102989042"/><file name="LICENSE_AFL.txt" hash="45a399f2095030865fb962263ccd7506"/><dir name="Model"><dir name="Mysql4"><dir name="User"><file name="Collection.php" hash="eee6af3b0c7ecf4f4a42eb0b50605d29"/></dir><file name="User.php" hash="296427f3d22c7cc18c0ece7c1afbc278"/></dir><file name="Observer.php" hash="ffb797d5cfc2f0724d20a44140661bed"/><file name="User.php" hash="9e3fad822b8adcd79dd5438d995fc61a"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ShipstationController.php" hash="c7cd0029ed2a0a46d7b16821b1e6a683"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="3021b17f108f3f50230194ff63975481"/><file name="api.xml" hash="3021b17f108f3f50230194ff63975481"/><file name="config.xml" hash="e0deae29ad3c4f83eefc6f23a7ea3953"/></dir><dir name="sql"><dir name="auctaneshipstation_setup"><file name="mysql4-install-1.0.0.php" hash="ab307db58a6d8ec97b5efc8d4eedb349"/></dir></dir></dir><dir name="Api"><dir name="Helper"><file name="Data.php" hash="e26b391ac0b9f0be29e1f127b2c7033e"/></dir><file name="LICENSE.html" hash="caf0a79ffb5e4719f9f4de286f253a61"/><file name="LICENSE.txt" hash="59563e7be45096d0833dade102989042"/><file name="LICENSE_AFL.txt" hash="45a399f2095030865fb962263ccd7506"/><dir name="Model"><dir name="Server"><file name="Adapter.php" hash="66a6914ed20bd925b630833d4f585638"/></dir><dir name="System"><dir name="Source"><dir name="Config"><file name="Customattributes.php" hash="a10dff7d323044151803ce2e30313615"/></dir></dir></dir></dir><dir name="controllers"><file name="AuctaneController.php" hash="b7100ac35e0b3a5d737cde7ef96e19c0"/></dir><dir name="etc"><file name="api.xml" hash="3b6279da3c6a4e5fc71c72f1caf94ae1"/><file name="config.xml" hash="921afbb817db09130827ac9d2f1fe033"/><file name="system.xml" hash="37d6921d13f1410dbb98f53925fba200"/></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="auctaneshipstation.xml" hash="d89f79f6de41bb4b23866356f16f48a1"/></dir><dir name="template"><dir name="auctane"><dir name="shipstation"><file name="container.phtml" hash="fb3df40a0baa33a21f6a51d52a90066c"/><file name="launch.phtml" hash="c3fbbc817cbf307fbd500defb2ab9f8e"/><file name="launchform.phtml" hash="b77583e98de80857b185d19a8ce03987"/><file name="linkup.phtml" hash="282a2114ca36efb68f1e681a29739a87"/><file name="pending.phtml" hash="100ec728f3b5ce479e09361bb22960bb"/></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><file name="Auctane_ShipStation.csv" hash="0f9582a3124a762cd6d9531f714d2f82"/></dir></target><target name="mageetc"><dir name="modules"><file name="Auctane_ShipStation.xml" hash="bacef7ff4049dece52644ec7be714ee6"/><file name="Auctane_Api.xml" hash="a27b534a3ad08732488959f8bdb72a03"/></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="images"><file name="shipstation.png" hash="e19a42099ef020edaf7c10d9a068c1c0"/></dir></dir></dir></dir></target></contents>
17
  <compatible/>
18
  <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
19
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Auctane_ShipStation</name>
4
+ <version>1.3.6</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
  <channel>community</channel>
9
  <summary>ShipStation is a web-based shipping solution that is integrated with the Magento API for retrieving order information and updating shipping details.</summary>
10
  <description>ShipStation is a web-based shipping solution that is integrated with the Magento API for retrieving order information and updating shipping details.</description>
11
  <notes>Official release.&#xD;
12
+ Capable of creating invoices and capturing payments when instructed to by ShipStation.</notes>
13
  <authors><author><name>clockworkgeek</name><user>nonproffessional</user><email>nonproffessional@clockworkgeek.com</email></author></authors>
14
+ <date>2013-05-07</date>
15
+ <time>14:03:40</time>
16
+ <contents><target name="magecommunity"><dir name="Auctane"><dir name="ShipStation"><dir name="Block"><dir name="Adminhtml"><dir name="Linkup"><file name="Form.php" hash="68b7c7bc627e89c304cf630c24aa5164"/></dir><file name="Linkup.php" hash="f280d1f6a26e74244898ea16cdf29c9b"/><file name="Pending.php" hash="6bc7a07b5d0b5192db32fefc55b94b08"/></dir></dir><dir name="Helper"><file name="Data.php" hash="cf2bd6a04dd7b88cae8096c2dd548214"/></dir><file name="LICENSE.html" hash="caf0a79ffb5e4719f9f4de286f253a61"/><file name="LICENSE.txt" hash="59563e7be45096d0833dade102989042"/><file name="LICENSE_AFL.txt" hash="45a399f2095030865fb962263ccd7506"/><dir name="Model"><dir name="Mysql4"><dir name="User"><file name="Collection.php" hash="eee6af3b0c7ecf4f4a42eb0b50605d29"/></dir><file name="User.php" hash="296427f3d22c7cc18c0ece7c1afbc278"/></dir><file name="Observer.php" hash="ffb797d5cfc2f0724d20a44140661bed"/><file name="User.php" hash="9e3fad822b8adcd79dd5438d995fc61a"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ShipstationController.php" hash="c7cd0029ed2a0a46d7b16821b1e6a683"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="3021b17f108f3f50230194ff63975481"/><file name="api.xml" hash="3021b17f108f3f50230194ff63975481"/><file name="config.xml" hash="8cf015e0374daa0959c959d6a4eabb09"/></dir><dir name="sql"><dir name="auctaneshipstation_setup"><file name="mysql4-install-1.0.0.php" hash="ab307db58a6d8ec97b5efc8d4eedb349"/></dir></dir></dir><dir name="Api"><dir name="Helper"><file name="Data.php" hash="0f99ca3811ec41b3b6672117d449305e"/></dir><file name="LICENSE.html" hash="caf0a79ffb5e4719f9f4de286f253a61"/><file name="LICENSE.txt" hash="59563e7be45096d0833dade102989042"/><file name="LICENSE_AFL.txt" hash="45a399f2095030865fb962263ccd7506"/><dir name="Model"><dir name="Action"><file name="Export.php" hash="a1b0531a6f8002386b4fa07b92573646"/><file name="Shipnotify.php" hash="c831fec09a6d5d0f4dd57b3aeb664ef8"/></dir><dir name="Server"><file name="Adapter.php" hash="c42a5c0968cf9bca320f6823212618b1"/></dir><dir name="System"><dir name="Source"><dir name="Config"><file name="Customattributes.php" hash="a10dff7d323044151803ce2e30313615"/></dir></dir></dir></dir><dir name="controllers"><file name="AuctaneController.php" hash="b7100ac35e0b3a5d737cde7ef96e19c0"/></dir><dir name="etc"><file name="api.xml" hash="3b6279da3c6a4e5fc71c72f1caf94ae1"/><file name="config.xml" hash="d3aa363a20a1cf1b72e5433ae4f3e043"/><file name="system.xml" hash="37d6921d13f1410dbb98f53925fba200"/></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="auctaneshipstation.xml" hash="d89f79f6de41bb4b23866356f16f48a1"/></dir><dir name="template"><dir name="auctane"><dir name="shipstation"><file name="container.phtml" hash="fb3df40a0baa33a21f6a51d52a90066c"/><file name="launch.phtml" hash="c3fbbc817cbf307fbd500defb2ab9f8e"/><file name="launchform.phtml" hash="b77583e98de80857b185d19a8ce03987"/><file name="linkup.phtml" hash="282a2114ca36efb68f1e681a29739a87"/><file name="pending.phtml" hash="100ec728f3b5ce479e09361bb22960bb"/></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><file name="Auctane_ShipStation.csv" hash="0f9582a3124a762cd6d9531f714d2f82"/></dir></target><target name="mageetc"><dir name="modules"><file name="Auctane_ShipStation.xml" hash="bacef7ff4049dece52644ec7be714ee6"/><file name="Auctane_Api.xml" hash="a27b534a3ad08732488959f8bdb72a03"/></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="images"><file name="shipstation.png" hash="e19a42099ef020edaf7c10d9a068c1c0"/></dir></dir></dir></dir></target></contents>
17
  <compatible/>
18
  <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
19
  </package>