1 package SL::ShopConnector::Shopware;
5 use parent qw(SL::ShopConnector::Base);
10 use LWP::Authen::Digest;
11 use SL::DB::ShopOrder;
12 use SL::DB::ShopOrderItem;
14 use DateTime::Format::Strptime;
17 use Sort::Naturally ();
18 use SL::Helper::Flash;
19 use Encode qw(encode_utf8);
23 use Rose::Object::MakeMethods::Generic (
24 'scalar --get_set_init' => [ qw(connector url) ],
31 my $ordnumber = $self->config->last_order_number + 1;
32 my $otf = $self->config->orders_to_fetch;
34 my $orders_data = $self->connector->get($url . "api/orders?limit=$otf&filter[0][property]=number&filter[0][expression]=>&filter[0][value]=" . $self->config->last_order_number);
35 my $orders_data_json = $orders_data->content;
36 my $orders_import = SL::JSON::decode_json($orders_data_json);
38 if ($orders_import->{success}){
39 foreach my $shoporder(@{ $orders_import->{data} }){
41 my $data = $self->connector->get($url . "api/orders/" . $shoporder->{id});
42 my $data_json = $data->content;
43 my $import = SL::JSON::decode_json($data_json);
45 $self->import_data_to_shop_order($import);
47 $self->config->assign_attributes( last_order_number => $ordnumber);
53 my $shop = $self->config->description;
54 my %fetched_orders = (shop_id => $self->config->description, number_of_orders => $of);
55 return \%fetched_orders;
58 sub import_data_to_shop_order {
59 my ( $self, $import ) = @_;
60 my $shop_order = $self->map_data_to_shoporder($import);
63 my $id = $shop_order->id;
65 my @positions = sort { Sort::Naturally::ncmp($a->{"partnumber"}, $b->{"partnumber"}) } @{ $import->{data}->{details} };
67 my $active_price_source = $self->config->price_source;
69 foreach my $pos(@positions) {
70 my $price = $::form->round_amount($pos->{price},2);
71 my %pos_columns = ( description => $pos->{articleName},
72 partnumber => $pos->{articleNumber},
74 quantity => $pos->{quantity},
75 position => $position,
76 tax_rate => $pos->{taxRate},
77 shop_trans_id => $pos->{articleId},
79 active_price_source => $active_price_source,
81 my $pos_insert = SL::DB::ShopOrderItem->new(%pos_columns);
85 $shop_order->{positions} = $position-1;
87 my $customer = $shop_order->get_customer;
90 $shop_order->kivi_customer_id($customer->id);
95 sub map_data_to_shoporder {
96 my ($self, $import) = @_;
98 my $parser = DateTime::Format::Strptime->new( pattern => '%Y-%m-%dT%H:%M:%S',
102 my $orderdate = $parser->parse_datetime($import->{data}->{orderTime});
104 my $shop_id = $self->config->id;
105 my $tax_included = $self->config->pricetype;
106 # Mapping to table shoporders. See http://community.shopware.com/_detail_1690.html#GET_.28Liste.29
108 amount => $import->{data}->{invoiceAmount},
109 billing_city => $import->{data}->{billing}->{city},
110 billing_company => $import->{data}->{billing}->{company},
111 billing_country => $import->{data}->{billing}->{country}->{name},
112 billing_department => $import->{data}->{billing}->{department},
113 billing_email => $import->{data}->{customer}->{email},
114 billing_fax => $import->{data}->{billing}->{fax},
115 billing_firstname => $import->{data}->{billing}->{firstName},
116 #billing_greeting => ($import->{data}->{billing}->{salutation} eq 'mr' ? 'Herr' : 'Frau'),
117 billing_lastname => $import->{data}->{billing}->{lastName},
118 billing_phone => $import->{data}->{billing}->{phone},
119 billing_street => $import->{data}->{billing}->{street},
120 billing_vat => $import->{data}->{billing}->{vatId},
121 billing_zipcode => $import->{data}->{billing}->{zipCode},
122 customer_city => $import->{data}->{billing}->{city},
123 customer_company => $import->{data}->{billing}->{company},
124 customer_country => $import->{data}->{billing}->{country}->{name},
125 customer_department => $import->{data}->{billing}->{department},
126 customer_email => $import->{data}->{customer}->{email},
127 customer_fax => $import->{data}->{billing}->{fax},
128 customer_firstname => $import->{data}->{billing}->{firstName},
129 #customer_greeting => ($import->{data}->{billing}->{salutation} eq 'mr' ? 'Herr' : 'Frau'),
130 customer_lastname => $import->{data}->{billing}->{lastName},
131 customer_phone => $import->{data}->{billing}->{phone},
132 customer_street => $import->{data}->{billing}->{street},
133 customer_vat => $import->{data}->{billing}->{vatId},
134 customer_zipcode => $import->{data}->{billing}->{zipCode},
135 customer_newsletter => $import->{data}->{customer}->{newsletter},
136 delivery_city => $import->{data}->{shipping}->{city},
137 delivery_company => $import->{data}->{shipping}->{company},
138 delivery_country => $import->{data}->{shipping}->{country}->{name},
139 delivery_department => $import->{data}->{shipping}->{department},
140 delivery_email => "",
141 delivery_fax => $import->{data}->{shipping}->{fax},
142 delivery_firstname => $import->{data}->{shipping}->{firstName},
143 #delivery_greeting => ($import->{data}->{shipping}->{salutation} eq 'mr' ? 'Herr' : 'Frau'),
144 delivery_lastname => $import->{data}->{shipping}->{lastName},
145 delivery_phone => $import->{data}->{shipping}->{phone},
146 delivery_street => $import->{data}->{shipping}->{street},
147 delivery_vat => $import->{data}->{shipping}->{vatId},
148 delivery_zipcode => $import->{data}->{shipping}->{zipCode},
149 host => $import->{data}->{shop}->{hosts},
150 netamount => $import->{data}->{invoiceAmountNet},
151 order_date => $orderdate,
152 payment_description => $import->{data}->{payment}->{description},
153 payment_id => $import->{data}->{paymentId},
154 remote_ip => $import->{data}->{remoteAddress},
155 sepa_account_holder => $import->{data}->{paymentIntances}->{accountHolder},
156 sepa_bic => $import->{data}->{paymentIntances}->{bic},
157 sepa_iban => $import->{data}->{paymentIntances}->{iban},
158 shipping_costs => $import->{data}->{invoiceShipping},
159 shipping_costs_net => $import->{data}->{invoiceShippingNet},
160 shop_c_billing_id => $import->{data}->{billing}->{customerId},
161 shop_c_billing_number => $import->{data}->{billing}->{number},
162 shop_c_delivery_id => $import->{data}->{shipping}->{id},
163 shop_customer_id => $import->{data}->{customerId},
164 shop_customer_number => $import->{data}->{billing}->{number},
165 shop_customer_comment => $import->{data}->{customerComment},
167 shop_ordernumber => $import->{data}->{number},
168 shop_trans_id => $import->{data}->{id},
169 tax_included => $tax_included eq "brutto" ? 1 : 0,
172 my $shop_order = SL::DB::ShopOrder->new(%columns);
179 my $url = $self->url;
180 my $data = $self->connector->get($url . "api/categories");
181 my $data_json = $data->content;
182 my $import = SL::JSON::decode_json($data_json);
183 my @daten = @{$import->{data}};
184 my %categories = map { ($_->{id} => $_) } @daten;
187 my $parent = $categories{$_->{parentId}};
188 $parent->{children} ||= [];
189 push @{$parent->{children}},$_;
198 my $url = $self->url;
199 my $data = $self->connector->get($url . "api/version");
200 my $type = $data->content_type;
201 my $status_line = $data->status_line;
203 if($data->is_success && $type eq 'application/json'){
204 my $data_json = $data->content;
205 return SL::JSON::decode_json($data_json);
207 my %return = ( success => 0,
208 data => { version => $url . ": " . $status_line, revision => $type },
209 message => "Server not found or wrong data type",
216 my ($self, $shop_part, $todo) = @_;
218 #shop_part is passed as a param
219 die unless ref($shop_part) eq 'SL::DB::ShopPart';
221 my $url = $self->url;
222 my $part = SL::DB::Part->new(id => $shop_part->{part_id})->load;
225 my $cvars = { map { ($_->config->name => { value => $_->value_as_text, is_valid => $_->is_valid }) } @{ $part->cvars_by_config } };
228 foreach my $row_cat ( @{ $shop_part->shop_category } ) {
229 my $temp = { ( id => @{$row_cat}[0], ) };
230 push ( @cat, $temp );
233 my @upload_img = $shop_part->get_images;
234 my $tax_n_price = $shop_part->get_tax_and_price;
235 my $price = $tax_n_price->{price};
236 my $taxrate = $tax_n_price->{tax};
237 # mapping to shopware still missing attributes,metatags
240 if($todo eq "price"){
241 %shop_data = ( mainDetail => { number => $part->{partnumber},
242 prices => [ { from => 1,
244 customerGroupKey => 'EK',
249 }elsif($todo eq "stock"){
250 %shop_data = ( mainDetail => { number => $part->{partnumber},
251 inStock => $part->{onhand},
254 }elsif($todo eq "price_stock"){
255 %shop_data = ( mainDetail => { number => $part->{partnumber},
256 inStock => $part->{onhand},
257 prices => [ { from => 1,
259 customerGroupKey => 'EK',
264 }elsif($todo eq "active"){
265 %shop_data = ( mainDetail => { number => $part->{partnumber},
267 active => ($part->{partnumber} == 1 ? 0 : 1),
269 }elsif($todo eq "all"){
270 # mapping to shopware still missing attributes,metatags
271 %shop_data = ( name => $part->{description},
272 mainDetail => { number => $part->{partnumber},
273 inStock => $part->{onhand},
274 prices => [ { from => 1,
276 customerGroupKey => 'EK',
279 #attribute => { attr1 => $cvars->{CVARNAME}->{value}, } , #HowTo handle attributes
281 supplier => 'AR', # Is needed by shopware,
282 descriptionLong => $shop_part->{shop_description},
283 active => $shop_part->active,
284 images => [ @upload_img ],
285 __options_images => { replace => 1, },
286 categories => [ @cat ],
287 description => $shop_part->{shop_description},
288 categories => [ @cat ],
294 my $dataString = SL::JSON::to_json(\%shop_data);
295 $dataString = encode_utf8($dataString);
299 my ($import,$data,$data_json);
300 my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
301 # Shopware RestApi sends an erroremail if configured and part not found. But it needs this info to decide if update or create a new article
302 # LWP->post = create LWP->put = update
303 $data = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
304 $data_json = $data->content;
305 $import = SL::JSON::decode_json($data_json);
306 if($import->{success}){
308 my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
309 $upload = $self->connector->put($url . "api/articles/$partnumber?useNumberAsId=true", Content => $dataString);
310 my $data_json = $upload->content;
311 $upload_content = SL::JSON::decode_json($data_json);
314 $upload = $self->connector->post($url . "api/articles/", Content => $dataString);
315 my $data_json = $upload->content;
316 $upload_content = SL::JSON::decode_json($data_json);
318 # don't know if this is needed
320 my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
321 my $imgup = $self->connector->put($url . "api/generatearticleimages/$partnumber?useNumberAsId=true");
324 return $upload_content->{success};
328 my ($self,$partnumber) = @_;
330 my $url = $self->url;
331 $partnumber = $::form->escape($partnumber);#shopware don't accept / in articlenumber
332 my $data = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
333 my $data_json = $data->content;
334 return SL::JSON::decode_json($data_json);
339 $self->url($self->config->protocol . "://" . $self->config->server . ":" . $self->config->port . $self->config->path);
344 my $ua = LWP::UserAgent->new;
346 $self->config->server . ":" . $self->config->port,
347 $self->config->realm,
348 $self->config->login => $self->config->password
363 SL::Shopconnecter::Shopware - connector for shopware 5
370 This is the connector to shopware.
371 In this file you can do the mapping to your needs.
372 see https://developers.shopware.com/developers-guide/rest-api/
373 for more information.
379 =item C<get_new_orders>
381 =item C<import_data_to_shop_order>
383 Creates on shoporder object from json
384 Here is the mapping for the positions.
385 see https://developers.shopware.com/developers-guide/rest-api/
386 for detailed information
388 =item C<map_data_to_shoporder>
390 Here is the mapping for the order data.
391 see https://developers.shopware.com/developers-guide/rest-api/
392 for detailed information
394 =item C<get_categories>
398 Use this for test Connection
403 Here is the mapping for the article data.
404 see https://developers.shopware.com/developers-guide/rest-api/
405 for detailed information
425 Pricesrules, pricessources aren't fully implemented yet.
426 Payments aren't implemented( need to map payments from Shopware like invoice, paypal etc. to payments in kivitendo)
434 W. Hahn E<lt>wh@futureworldsearch.netE<gt>