Revision ce1ca334
Von Werner Hahn vor mehr als 7 Jahren hinzugefügt
SL/BackgroundJob/ShopPartMassUpload.pm | ||
---|---|---|
package SL::BackgroundJob::ShopPartMassUpload;
|
||
#ShopPartMassUpload
|
||
|
||
use strict;
|
||
use warnings;
|
||
|
||
... | ... | |
|
||
use SL::DBUtils;
|
||
use SL::DB::ShopPart;
|
||
use SL::Shop;
|
||
use SL::Shop;
|
||
|
||
use constant WAITING_FOR_EXECUTION => 0;
|
||
use constant UPLOAD_TO_WEBSHOP => 1;
|
||
... | ... | |
|
||
# Data format:
|
||
# my $data = {
|
||
# shop_part_record_ids => [ 603, 604, 605],
|
||
# num_order_created => 0,
|
||
# orders_ids => [1,2,3]
|
||
# conversation_errors => [ { id => 603 , item => 2, message => "Out of stock"}, ],
|
||
# shop_part_record_ids => [ 603, 604, 605 ],
|
||
# todo => $::form->{upload_todo},
|
||
# status => SL::BackgroundJob::ShopPartMassUpload->WAITING_FOR_EXECUTION(),
|
||
# num_uploaded => 0,
|
||
# conversation => [ { id => 603 , number => 2, message => "Ok" or $@ }, ],
|
||
# };
|
||
|
||
sub update_webarticles {
|
||
... | ... | |
my $db = $job_obj->db;
|
||
|
||
$job_obj->set_data(UPLOAD_TO_WEBSHOP())->save;
|
||
|
||
my $num_uploaded = 0;
|
||
foreach my $shop_part_id (@{ $job_obj->data_as_hash->{shop_part_record_ids} }) {
|
||
my $data = $job_obj->data_as_hash;
|
||
eval {
|
||
my $shop_part = SL::DB::Manager::ShopPart->find_by(id => $shop_part_id);
|
||
unless($shop_part){
|
||
push @{ $data->{conversion_errors} }, { id => $shop_part_id, number => '', message => 'Shoppart not found' };
|
||
push @{ $data->{conversion} }, { id => $shop_part_id, number => '', message => 'Shoppart not found' };
|
||
}
|
||
|
||
my $shop = SL::Shop->new( config => $shop_part->shop );
|
||
|
||
my $part_hash = $shop_part->part->as_tree;
|
||
require SL::JSON;
|
||
|
||
my $json = SL::JSON::to_json($part_hash);
|
||
my $return = $shop->connector->update_part($shop_part, $json, $data->{todo});
|
||
my $return = $shop->connector->update_part($shop_part, $data->{todo});
|
||
if ( $return == 1 ) {
|
||
my $now = DateTime->now;
|
||
my $attributes->{last_update} = $now;
|
||
$shop_part->assign_attributes(%{ $attributes });
|
||
$shop_part->save;
|
||
$data->{num_uploaded} = $num_uploaded++;
|
||
push @{ $data->{conversion} }, { id => $shop_part_id, number => $shop_part->part->partnumber, message => 'uploaded' };
|
||
}else{
|
||
push @{ $data->{conversion_errors} }, { id => $shop_part_id, number => '', message => $return };
|
||
push @{ $data->{conversion} }, { id => $shop_part_id, number => $shop_part->part->partnumber, message => $return };
|
||
}
|
||
1;
|
||
} or do {
|
||
push @{ $data->{conversion_errors} }, { id => $shop_part_id, number => '', message => $@ };
|
||
push @{ $data->{conversion} }, { id => $shop_part_id, number => '', message => $@ };
|
||
};
|
||
|
||
$job_obj->update_attributes(data_as_hash => $data);
|
SL/Controller/ShopPart.pm | ||
---|---|---|
require SL::Shop;
|
||
my $shop = SL::Shop->new( config => $shop_part->shop );
|
||
|
||
my $part_hash = $shop_part->part->as_tree;
|
||
my $json = SL::JSON::to_json($part_hash);
|
||
my $return = $shop->connector->update_part($self->shop_part, $json,'all');
|
||
my $return = $shop->connector->update_part($self->shop_part, 'all');
|
||
|
||
# the connector deals with parsing/result verification, just needs to return success or failure
|
||
if ( $return == 1 ) {
|
||
... | ... | |
|
||
}
|
||
|
||
sub action_update {
|
||
my ($self) = @_;
|
||
|
||
$self->create_or_update;
|
||
}
|
||
|
||
sub action_show_price_n_pricesource {
|
||
my ($self) = @_;
|
||
|
||
... | ... | |
my $online_cat = $online_article->{data}->{categories};
|
||
my @cat = ();
|
||
for(keys %$online_cat){
|
||
# The ShopwareConnector works with the CategoryID @categories[x][0] in others/new Connectors it must be tested
|
||
# Each assigned categorie is saved with id,categorie_name an multidimensional array and could be expanded with categoriepath or what is needed
|
||
my @cattmp;
|
||
push( @cattmp,$online_cat->{$_}->{id} );
|
||
push( @cattmp,$online_cat->{$_}->{name} );
|
||
push( @cat,\@cattmp );
|
||
push @cattmp,$online_cat->{$_}->{id};
|
||
push @cattmp,$online_cat->{$_}->{name};
|
||
push @cat,\@cattmp;
|
||
}
|
||
my $attributes->{shop_category} = \@cat;
|
||
my $active->{active} = $online_article->{data}->{active};
|
||
... | ... | |
$self->redirect_to( action => 'list_articles' );
|
||
}
|
||
|
||
sub create_or_update {
|
||
my ($self) = @_;
|
||
|
||
my $is_new = !$self->shop_part->id;
|
||
|
||
# in edit.html all variables start with shop_part
|
||
my $params = delete($::form->{shop_part}) || { };
|
||
|
||
$self->shop_part->assign_attributes(%{ $params });
|
||
|
||
$self->shop_part->save;
|
||
|
||
my ( $price, $price_src_str ) = $self->get_price_n_pricesource($self->shop_part->active_price_source);
|
||
|
||
flash('info', $is_new ? t8('The shop part has been created.') : t8('The shop part has been saved.'));
|
||
$self->js->html('#shop_part_description_' . $self->shop_part->id, $self->shop_part->shop_description)
|
||
->html('#shop_part_active_' . $self->shop_part->id, $self->shop_part->active)
|
||
->html('#price_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$price,2))
|
||
->html('#active_price_source_' . $self->shop_part->id, $price_src_str)
|
||
->run('kivi.ShopPart.close_dialog')
|
||
->flash('info', t8("Updated shop part"))
|
||
->render;
|
||
}
|
||
|
||
sub render_shop_part_edit_dialog {
|
||
my ($self) = @_;
|
||
|
||
# when self->shop_part is called in template, it will be an existing shop_part with id,
|
||
# or a new shop_part with only part_id and shop_id set
|
||
$self->js
|
||
->run(
|
||
'kivi.ShopPart.shop_part_dialog',
|
||
t8('Shop part'),
|
||
$self->render('shop_part/edit', { output => 0 })
|
||
)
|
||
->reinit_widgets;
|
||
|
||
$self->js->render;
|
||
}
|
||
|
||
sub action_save_categories {
|
||
my ($self) = @_;
|
||
|
||
my @categories = @{ $::form->{categories} || [] };
|
||
|
||
# The ShopwareConnector works with the CategoryID @categories[x][0] in others/new Connectors it must be tested
|
||
# Each assigned categorie is saved with id,categorie_name an multidimensional array and could be expanded with categoriepath or what is needed
|
||
my @cat = ();
|
||
foreach my $cat ( @categories) {
|
||
my @cattmp;
|
||
... | ... | |
|
||
my @shop_parts = @{ $::form->{shop_parts_ids} || [] };
|
||
|
||
my $job = SL::DB::BackgroundJob->new(
|
||
type => 'once',
|
||
active => 1,
|
||
package_name => 'ShopPartMassUpload',
|
||
)->set_data(
|
||
shop_part_record_ids => [ @shop_parts ],
|
||
todo => $::form->{upload_todo},
|
||
status => SL::BackgroundJob::ShopPartMassUpload->WAITING_FOR_EXECUTION(),
|
||
conversation_errors => [ ],
|
||
my $job = SL::DB::BackgroundJob->new(
|
||
type => 'once',
|
||
active => 1,
|
||
package_name => 'ShopPartMassUpload',
|
||
)->set_data(
|
||
shop_part_record_ids => [ @shop_parts ],
|
||
todo => $::form->{upload_todo},
|
||
status => SL::BackgroundJob::ShopPartMassUpload->WAITING_FOR_EXECUTION(),
|
||
conversation => [ ],
|
||
num_uploaded => 0,
|
||
)->update_next_run_at;
|
||
|
||
SL::System::TaskServer->new->wake_up;
|
||
|
||
my $html = $self->render('shop_part/_transfer_status', { output => 0 }, job => $job);
|
||
my $html = $self->render('shop_part/_upload_status', { output => 0 }, job => $job);
|
||
|
||
$self->js
|
||
->html('#status_mass_upload', $html)
|
||
... | ... | |
->render;
|
||
}
|
||
|
||
sub action_update {
|
||
my ($self) = @_;
|
||
|
||
$self->create_or_update;
|
||
}
|
||
|
||
sub render_shop_part_edit_dialog {
|
||
my ($self) = @_;
|
||
|
||
$self->js
|
||
->run(
|
||
'kivi.ShopPart.shop_part_dialog',
|
||
t8('Shop part'),
|
||
$self->render('shop_part/edit', { output => 0 })
|
||
)
|
||
->reinit_widgets;
|
||
|
||
$self->js->render;
|
||
}
|
||
|
||
sub create_or_update {
|
||
my ($self) = @_;
|
||
|
||
my $is_new = !$self->shop_part->id;
|
||
|
||
my $params = delete($::form->{shop_part}) || { };
|
||
|
||
$self->shop_part->assign_attributes(%{ $params });
|
||
|
||
$self->shop_part->save;
|
||
|
||
my ( $price, $price_src_str ) = $self->get_price_n_pricesource($self->shop_part->active_price_source);
|
||
|
||
flash('info', $is_new ? t8('The shop part has been created.') : t8('The shop part has been saved.'));
|
||
$self->js->html('#shop_part_description_' . $self->shop_part->id, $self->shop_part->shop_description)
|
||
->html('#shop_part_active_' . $self->shop_part->id, $self->shop_part->active)
|
||
->html('#price_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$price,2))
|
||
->html('#active_price_source_' . $self->shop_part->id, $price_src_str)
|
||
->run('kivi.ShopPart.close_dialog')
|
||
->flash('info', t8("Updated shop part"))
|
||
->render;
|
||
}
|
||
|
||
#
|
||
# internal stuff
|
||
#
|
||
... | ... | |
sub load_pricesources {
|
||
my ($self) = @_;
|
||
|
||
# the price sources to use for the article: sellprice, lastcost,
|
||
# listprice, or one of the pricegroups. It overwrites the default pricesource from the shopconfig.
|
||
# TODO: implement valid pricerules for the article
|
||
my $pricesources;
|
||
push( @{ $pricesources } , { id => "master_data/sellprice", name => t8("Master Data")." - ".t8("Sellprice") },
|
||
{ id => "master_data/listprice", name => t8("Master Data")." - ".t8("Listprice") },
|
||
{ id => "master_data/lastcost", name => t8("Master Data")." - ".t8("Lastcost") }
|
||
{ id => "master_data/lastcost", nam => t8("Master Data")." - ".t8("Lastcost") }
|
||
);
|
||
my $pricegroups = SL::DB::Manager::Pricegroup->get_all;
|
||
foreach my $pg ( @$pricegroups ) {
|
||
... | ... | |
require SL::DB::Part;
|
||
my $price;
|
||
if ($price_src_str eq "master_data") {
|
||
my $part = SL::DB::Manager::Part->get_all( where => [id => $self->shop_part->part_id], with_objects => ['prices'],limit => 1)->[0];
|
||
my $part = SL::DB::Manager::Part->find_by( id => $self->shop_part->part_id );
|
||
$price = $part->$price_src_id;
|
||
$price_src_str = $price_src_id;
|
||
}else{
|
||
my $part = SL::DB::Manager::Part->get_all( where => [id => $self->shop_part->part_id, 'prices.'.pricegroup_id => $price_src_id], with_objects => ['prices'],limit => 1)->[0];
|
||
#my $part = SL::DB::Manager::Part->find_by( id => $self->shop_part->part_id, 'prices.'.pricegroup_id => $price_src_id );
|
||
my $pricegrp = SL::DB::Manager::Pricegroup->find_by( id => $price_src_id )->pricegroup;
|
||
$price = $part->prices->[0]->price;
|
||
$price_src_str = $pricegrp;
|
||
... | ... | |
}
|
||
|
||
sub init_shops {
|
||
# data for drop down filter options
|
||
require SL::DB::Shop;
|
||
my @shops_dd = [ { title => t8("all") , value =>'' } ];
|
||
my $shops = SL::DB::Mangager::Shop->get_all( where => [ obsolete => 0 ] );
|
||
my @tmp = map { { title => $_->{description}, value => $_->{id} } } @{ $shops } ;
|
||
return @shops_dd;
|
||
|
||
}
|
||
|
||
sub init_producers {
|
||
# data for drop down filter options
|
||
my @producers_dd = [ { title => t8("all") , value =>'' } ];
|
||
return @producers_dd;
|
||
|
||
}
|
||
|
||
1;
|
||
... | ... | |
|
||
=head1 NAME
|
||
|
||
SL::Controller::ShopPart - Controller for managing ShopParts
|
||
SL::Controller::ShopPart - Controller for managing ShopParts
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
ShopParts are configured in a tab of the corresponding part.
|
||
|
||
=head1 FUNCTIONS
|
||
ShopParts are configured in a tab of the corresponding part.
|
||
|
||
=head1 ACTIONS
|
||
|
||
=over 4
|
||
|
||
=item C<action_update_shop>
|
||
|
||
To be called from the "Update" button of the shoppart, for manually syncing/upload one part with its shop. Generates a Calls some ClientJS functions to modifiy original page.
|
||
To be called from the "Update" button of the shoppart, for manually syncing/upload one part with its shop. Calls some ClientJS functions to modifiy original page.
|
||
|
||
=item C<action_show_files>
|
||
|
||
|
||
|
||
=item C<action_ajax_delete_file>
|
||
|
||
|
||
|
||
=item C<action_get_categories>
|
||
|
||
|
||
|
||
=item C<action_show_price_n_pricesource>
|
||
|
||
|
||
|
||
=item C<action_show_stock>
|
||
|
||
|
||
|
||
=item C<action_get_n_write_categories>
|
||
|
||
Can be used to sync the categories of a shoppart with the categories from online.
|
||
Can be used to sync the categories of a shoppart with the categories from online.
|
||
|
||
=item C<action_save_categories>
|
||
|
||
The ShopwareConnector works with the CategoryID @categories[x][0] in others/new Connectors it must be tested
|
||
Each assigned categorie is saved with id,categorie_name an multidimensional array and could be expanded with categoriepath or what is needed
|
||
|
||
=item C<action_reorder>
|
||
|
||
|
||
|
||
=item C<action_upload_status>
|
||
|
||
|
||
|
||
=item C<action_mass_upload>
|
||
|
||
|
||
|
||
=item C<action_update>
|
||
|
||
|
||
|
||
=item C<create_or_update>
|
||
|
||
|
||
|
||
=item C<render_shop_part_edit_dialog>
|
||
|
||
when self->shop_part is called in template, it will be an existing shop_part with id,
|
||
or a new shop_part with only part_id and shop_id set
|
||
|
||
=item C<add_javascripts>
|
||
|
||
|
||
=item C<load_pricesources>
|
||
|
||
the price sources to use for the article: sellprice, lastcost,
|
||
listprice, or one of the pricegroups. It overwrites the default pricesource from the shopconfig.
|
||
TODO: implement valid pricerules for the article
|
||
|
||
=item C<get_price_n_pricesource>
|
||
|
||
|
||
=item C<check_auth>
|
||
|
||
|
||
=item C<init_shop_part>
|
||
|
||
|
||
=item C<init_file>
|
||
|
||
|
||
=item C<init_shops>
|
||
|
||
data for drop down filter options
|
||
|
||
=back
|
||
|
||
=head1 TODO
|
||
|
||
Pricesrules, pricessources aren't fully implemented yet.
|
||
CheckAuth
|
||
Pricesrules, pricessources aren't fully implemented yet.
|
||
|
||
=head1 AUTHORS
|
||
|
||
G. Richardson E<lt>information@kivitendo-premium.deE<gt>
|
||
W. Hahn E<lt>wh@futureworldsearch.netE<gt>
|
||
G. Richardson E<lt>information@kivitendo-premium.deE<gt>
|
||
W. Hahn E<lt>wh@futureworldsearch.netE<gt>
|
||
|
||
=cut
|
SL/DB/ShopPart.pm | ||
---|---|---|
|
||
use strict;
|
||
|
||
use SL::DBUtils;
|
||
use SL::DB::MetaSetup::ShopPart;
|
||
use SL::DB::Manager::ShopPart;
|
||
use SL::DB::Helper::AttrHTML;
|
||
... | ... | |
__PACKAGE__->meta->initialize;
|
||
__PACKAGE__->attr_html('shop_description');
|
||
|
||
sub get_tax_and_price {
|
||
my ( $self ) = @_;
|
||
|
||
require SL::DB::Part;
|
||
my $tax_n_price;
|
||
my ( $price_src_str, $price_src_id ) = split(/\//,$self->active_price_source);
|
||
my $price;
|
||
my $part;
|
||
if ($price_src_str eq "master_data") {
|
||
$part = SL::DB::Manager::Part->find_by( id => $self->part_id );
|
||
$price = $part->$price_src_id;
|
||
}else{
|
||
$part = SL::DB::Manager::Part->find_by( id => $self->part_id );
|
||
$price = $part->prices->[0]->price;
|
||
}
|
||
|
||
my $taxrate;
|
||
my $dbh = $::form->get_standard_dbh();
|
||
my $b_id = $part->buchungsgruppen_id;
|
||
my $t_id = $self->shop->taxzone_id;
|
||
|
||
my $sql_str = "SELECT a.rate AS taxrate from tax a
|
||
WHERE a.taxkey = (SELECT b.taxkey_id
|
||
FROM chart b LEFT JOIN taxzone_charts c ON b.id = c.income_accno_id
|
||
WHERE c.taxzone_id = $t_id
|
||
AND c.buchungsgruppen_id = $b_id)";
|
||
|
||
my $rate = selectall_hashref_query($::form, $dbh, $sql_str);
|
||
$taxrate = @$rate[0]->{taxrate}*100;
|
||
|
||
$tax_n_price->{price} = $price;
|
||
$tax_n_price->{tax} = $taxrate;
|
||
return $tax_n_price;
|
||
}
|
||
|
||
sub get_images {
|
||
my ( $self ) = @_;
|
||
|
||
require SL::DB::ShopImage;
|
||
my $images = SL::DB::Manager::ShopImage->get_all( where => [ 'files.object_id' => $self->{part_id}, ], with_objects => 'file', sort_by => 'position' );
|
||
my @upload_img = ();
|
||
foreach my $img (@{ $images }) {
|
||
my $file = SL::File->get(id => $img->file->id );
|
||
my ($path, $extension) = (split /\./, $file->file_name);
|
||
my $content = File::Slurp::read_file($file->get_file);
|
||
my $temp ={ ( link => 'data:' . $file->mime_type . ';base64,' . MIME::Base64::encode($content, ""), #$content, # MIME::Base64::encode($content),
|
||
description => $img->file->title,
|
||
position => $img->position,
|
||
extension => $extension,
|
||
path => $path,
|
||
)} ;
|
||
push( @upload_img, $temp);
|
||
}
|
||
return @upload_img;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=pod
|
||
|
||
=encoding utf-8
|
||
|
||
=head1 NAME
|
||
|
||
SL::DB::ShopPart - Model for the 'shop_parts' table
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
This is a standard Rose::DB::Object based model and can be used as one.
|
||
|
||
=head1 METHODS
|
||
|
||
=over 4
|
||
|
||
=item C<get_tax_and_price>
|
||
|
||
Returns the price and the taxrate for an shop_article
|
||
|
||
=item C<get_images>
|
||
|
||
Returns the images for the shop_article
|
||
|
||
=back
|
||
|
||
=head1 TODO
|
||
|
||
Prices, pricesources, pricerules could be implemented
|
||
|
||
=head1 AUTHORS
|
||
|
||
Werner Hahn E<lt>wh@futureworldsearch.netE<gt>
|
||
|
||
=cut
|
SL/ShopConnector/Shopware.pm | ||
---|---|---|
}
|
||
|
||
sub update_part {
|
||
my ($self, $shop_part, $json, $todo) = @_;
|
||
my ($self, $shop_part, $todo) = @_;
|
||
|
||
#shop_part is passed as a param
|
||
die unless ref($shop_part) eq 'SL::DB::ShopPart';
|
||
... | ... | |
my $url = $self->url;
|
||
my $part = SL::DB::Part->new(id => $shop_part->{part_id})->load;
|
||
|
||
# TODO: Prices (pricerules, pricegroups, multiple prices)
|
||
# CVARS to map
|
||
my $cvars = { map { ($_->config->name => { value => $_->value_as_text, is_valid => $_->is_valid }) } @{ $part->cvars_by_config } };
|
||
|
||
my @cat = ();
|
||
... | ... | |
push ( @cat, $temp );
|
||
}
|
||
|
||
my $images = SL::DB::Manager::ShopImage->get_all( where => [ 'files.object_id' => $part->{id}, ], with_objects => 'file', sort_by => 'position' );
|
||
my @upload_img = ();
|
||
foreach my $img (@{ $images }) {
|
||
my $file = SL::File->get(id => $img->file->id );
|
||
my ($path, $extension) = (split /\./, $file->file_name);
|
||
my $content = File::Slurp::read_file($file->get_file);
|
||
my $temp ={ ( link => 'data:' . $file->mime_type . ';base64,' . MIME::Base64::encode($content, ""), #$content, # MIME::Base64::encode($content),
|
||
description => $img->file->title,
|
||
position => $img->position,
|
||
extension => $extension,
|
||
path => $path,
|
||
)} ;
|
||
push( @upload_img, $temp);
|
||
}
|
||
|
||
my ($import,$data,$data_json);
|
||
# if( $shop_part->last_update){
|
||
my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
|
||
# Shopware RestApi schreibt Fehleremail wenn Artikel nicht gefunden. es braucht aber irgendeine Abfrage, ob der Artikel schon im Shop ist.
|
||
# LWP->post = neuanlegen LWP->put = update
|
||
$data = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
|
||
$data_json = $data->content;
|
||
$import = SL::JSON::decode_json($data_json);
|
||
# }
|
||
|
||
# get the right price
|
||
# TODO In extra Helper??
|
||
my ( $price_src_str, $price_src_id ) = split(/\//,$shop_part->active_price_source);
|
||
require SL::DB::Part;
|
||
my $price;
|
||
if ($price_src_str eq "master_data") {
|
||
my $part = SL::DB::Manager::Part->get_all( where => [id => $shop_part->part_id], with_objects => ['prices'],limit => 1)->[0];
|
||
$price = $part->$price_src_id;
|
||
}else{
|
||
my $part = SL::DB::Manager::Part->get_all( where => [id => $shop_part->part_id, 'prices.'.pricegroup_id => $price_src_id], with_objects => ['prices'],limit => 1)->[0];
|
||
$price = $part->prices->[0]->price;
|
||
}
|
||
|
||
# get the right taxrate for the article
|
||
# TODO In extra Helper??
|
||
my $taxrate;
|
||
my $dbh = $::form->get_standard_dbh();
|
||
my $b_id = $part->buchungsgruppen_id;
|
||
my $t_id = $shop_part->shop->taxzone_id;
|
||
|
||
my $sql_str = "SELECT a.rate AS taxrate from tax a
|
||
WHERE a.taxkey = (SELECT b.taxkey_id
|
||
FROM chart b LEFT JOIN taxzone_charts c ON b.id = c.income_accno_id
|
||
WHERE c.taxzone_id = $t_id
|
||
AND c.buchungsgruppen_id = $b_id)";
|
||
|
||
my $rate = selectall_hashref_query($::form, $dbh, $sql_str);
|
||
$taxrate = @$rate[0]->{taxrate}*100;
|
||
|
||
my @upload_img = $shop_part->get_images;
|
||
my $tax_n_price = $shop_part->get_tax_and_price;
|
||
my $price = $tax_n_price->{price};
|
||
my $taxrate = $tax_n_price->{tax};
|
||
# mapping to shopware still missing attributes,metatags
|
||
my %shop_data;
|
||
|
||
... | ... | |
|
||
my $upload_content;
|
||
my $upload;
|
||
my ($import,$data,$data_json);
|
||
my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
|
||
# 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
|
||
# LWP->post = create LWP->put = update
|
||
$data = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
|
||
$data_json = $data->content;
|
||
$import = SL::JSON::decode_json($data_json);
|
||
if($import->{success}){
|
||
#update
|
||
my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
|
||
... | ... | |
# don't know if this is needed
|
||
if(@upload_img) {
|
||
my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
|
||
my $imgup = $self->connector->put($url . "api/generatearticleimages/$partnumber?usenumberasid=true");
|
||
my $imgup = $self->connector->put($url . "api/generatearticleimages/$partnumber?useNumberAsId=true");
|
||
}
|
||
|
||
return $upload_content->{success};
|
||
... | ... | |
|
||
my $url = $self->url;
|
||
$partnumber = $::form->escape($partnumber);#shopware don't accept / in articlenumber
|
||
my $data = $self->connector->get($url . "api/articles/$partnumber?usenumberasid=true");
|
||
my $data = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
|
||
my $data_json = $data->content;
|
||
return SL::JSON::decode_json($data_json);
|
||
}
|
js/kivi.ShopPart.js | ||
---|---|---|
namespace('kivi.ShopPart', function(ns) {
|
||
var $dialog;
|
||
|
||
// this is called by sub render, with a certain prerendered html (edit.html,categories.html)
|
||
ns.shop_part_dialog = function(title, html) {
|
||
var id = 'jqueryui_popup_dialog';
|
||
var dialog_params = {
|
||
... | ... | |
$dialog.dialog("close");
|
||
}
|
||
|
||
|
||
// save existing shop_part_id with new params from form, calls create_or_update and saves to db
|
||
ns.save_shop_part = function(shop_part_id) {
|
||
var form = $('form').serializeArray();
|
||
form.push( { name: 'action', value: 'ShopPart/update' }
|
||
... | ... | |
});
|
||
}
|
||
|
||
// add part to a shop
|
||
ns.add_shop_part = function(part_id,shop_id) {
|
||
var form = $('form').serializeArray();
|
||
form.push( { name: 'action', value: 'ShopPart/update' }
|
||
... | ... | |
});
|
||
}
|
||
|
||
// this is called from tabs/_shop.html, opens edit_window (render)
|
||
ns.edit_shop_part = function(shop_part_id) {
|
||
$.post('controller.pl', { action: 'ShopPart/create_or_edit_popup', shop_part_id: shop_part_id }, function(data) {
|
||
kivi.eval_json_result(data);
|
||
});
|
||
}
|
||
|
||
// does the same as edit_shop_part (existing), but with part_id and shop_id, opens edit window (render)
|
||
ns.create_shop_part = function(part_id, shop_id) {
|
||
$.post('controller.pl', { action: 'ShopPart/create_or_edit_popup', part_id: part_id, shop_id: shop_id }, function(data) {
|
||
kivi.eval_json_result(data);
|
||
});
|
||
}
|
||
|
||
// gets all categories from the webshop
|
||
ns.get_all_categories = function(shop_part_id) {
|
||
//var form = new Array; //$('form').serializeArray();
|
||
//form.push( { name: 'action', value: 'ShopPart/get_categories' }
|
||
// , { name: 'shop_part_id', value: shop_part_id }
|
||
//);
|
||
$.post('controller.pl', { action: 'ShopPart/get_categories', shop_part_id: shop_part_id }, function(data) {
|
||
kivi.eval_json_result(data);
|
||
});
|
||
//$.post('controller.pl', form, function(data) {
|
||
// kivi.eval_json_result(data);
|
||
//});
|
||
}
|
||
// write categories in kivi DB not in the shops DB TODO: create new categories in the shops db
|
||
|
||
ns.save_categories = function(shop_part_id, shop_id) {
|
||
var form = $('form').serializeArray();
|
||
form.push( { name: 'action', value: 'ShopPart/save_categories' }
|
||
... | ... | |
$('#shop_images').load(url);
|
||
}
|
||
|
||
//shows the Name and price in _shop.html. Pricerules not implemented yet, just master_data and pricegroups
|
||
ns.update_price_n_price_source = function(shop_part_id,price_source) {
|
||
$.post('controller.pl', { action: 'ShopPart/show_price_n_pricesource', shop_part_id: shop_part_id, pricesource: price_source }, function(data) {
|
||
kivi.eval_json_result(data);
|
||
});
|
||
}
|
||
//shows the local and the online stock
|
||
|
||
ns.update_stock = function(shop_part_id) {
|
||
$.post('controller.pl', { action: 'ShopPart/show_stock', shop_part_id: shop_part_id }, function(data) {
|
||
kivi.eval_json_result(data);
|
templates/webpages/shop_part/_list_articles.html | ||
---|---|---|
</td>
|
||
<td style="vertical-align:middle;text-align:center;">
|
||
[% IF shop_part.active %]
|
||
<div id="toogle_[% shop_part.id %]" style="background-image:url(image/gruener_punkt.gif);background-repeat:no-repeat;witdh:15px;height:15px;" onclick="kivi.ShopPart.part_toggle_active([% shop_part.id %] ,[% shop_part.active %]);" onMouseOver="this.style.cursor='pointer'"> </div>
|
||
<div id="toogle_[% shop_part.id %]" style="background-image:url(image/gruener_punkt.gif);background-repeat:no-repeat;witdh:15px;height:15px;"> </div>
|
||
[% ELSE %]
|
||
<div id="toogle_[% shop_part.id %]" style="background-image:url(image/roter_punkt.gif);background-repeat:no-repeat;witdh:15px;height:15px;" onclick="kivi.ShopPart.part_toggle_active([% shop_part.id %] ,[% shop_part.active %]);" onMouseOver="this.style.cursor='pointer'"> </div>
|
||
<div id="toogle_[% shop_part.id %]" style="background-image:url(image/roter_punkt.gif);background-repeat:no-repeat;witdh:15px;height:15px;"> </div>
|
||
[% END %]
|
||
</td>
|
||
<td>[% L.html_tag('span',LxERP.t8(), id => 'active_price_source_' _ shop_part.id) %] </td>
|
templates/webpages/shop_part/_transfer_status.html | ||
---|---|---|
[% IF !data.status %]
|
||
[% LxERP.t8("waiting for job to be started") %]
|
||
[% ELSIF data.status == 1 %]
|
||
[% LxERP.t8("Creating orders") %]
|
||
[% LxERP.t8("Uploading Data") %]
|
||
[% ELSE %]
|
||
[% LxERP.t8("Done.") %]
|
||
[% END %]
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th valign="top" align="left">[% LxERP.t8("Number of orders created:") %]</th>
|
||
<td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_created) %] / [% HTML.escape(data.record_ids.size) %][% ELSE %]–[% END %]</td>
|
||
<th valign="top" align="left">[% LxERP.t8("Number of data uploaded:") %]</th>
|
||
<td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_uploaded) %] / [% HTML.escape(data.record_ids.size) %][% ELSE %]–[% END %]</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<th valign="top" align="left">[% LxERP.t8("Errors during conversion:") %]</th>
|
||
<th valign="top" align="left">[% LxERP.t8("Conversion:") %]</th>
|
||
<td valign="top">
|
||
[% IF !data.status %]
|
||
–
|
||
[% ELSIF !data.conversion_errors.size %]
|
||
[% LxERP.t8("No errors have occurred.") %]
|
||
[% ELSE %]
|
||
<table>
|
||
<tr class="listheader">
|
||
<th>[% LxERP.t8("Shop Order") %]</th>
|
||
<th>[% LxERP.t8("Error") %]</th>
|
||
<th>[% LxERP.t8("Part") %]</th>
|
||
<th>[% LxERP.t8("Partnumber") %]</th>
|
||
<th>[% LxERP.t8("Message") %]</th>
|
||
</tr>
|
||
|
||
[% FOREACH error = data.conversion_errors %]
|
||
[% FOREACH message = data.conversion %]
|
||
<tr>
|
||
<td valign="top">[% IF error.id %][% L.link(SELF.url_for(controller='ShopOrder', action='show', id=error.id), HTML.escape(error.number), target="_blank") %][% ELSE %]–[% END %]</td>
|
||
<td valign="top">[% HTML.escape(error.message) %]</td>
|
||
<td valign="top">[% HTML.escape(message.message) %]</td>
|
||
</tr>
|
||
[% END %]
|
||
</table>
|
templates/webpages/shop_part/_upload_status.html | ||
---|---|---|
[%- USE Dumper -%]
|
||
[% SET data = job.data_as_hash %]
|
||
|
||
|
||
<h2>[% LxERP.t8("Watch status") %]</h2>
|
||
|
||
[% L.hidden_tag('', job.id, id="smu_job_id") %]
|
||
... | ... | |
[% IF !data.status %]
|
||
[% LxERP.t8("waiting for job to be started") %]
|
||
[% ELSIF data.status == 1 %]
|
||
[% LxERP.t8("Creating orders") %]
|
||
[% LxERP.t8("Uploading Data") %]
|
||
[% ELSE %]
|
||
[% LxERP.t8("Done.") %]
|
||
[% END %]
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th valign="top" align="left">[% LxERP.t8("Number of orders created:") %]</th>
|
||
<td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_created) %] / [% HTML.escape(data.record_ids.size) %][% ELSE %]–[% END %]</td>
|
||
<th valign="top" align="left">[% LxERP.t8("Number of data uploaded:") %]</th>
|
||
<td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_uploaded) %] / [% HTML.escape(data.shop_part_record_ids.size) %][% ELSE %]–[% END %]</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<th valign="top" align="left">[% LxERP.t8("Errors during conversion:") %]</th>
|
||
<th valign="top" align="left">[% LxERP.t8("Conversion:") %]</th>
|
||
<td valign="top">
|
||
[% IF !data.status %]
|
||
–
|
||
[% ELSIF !data.conversion_errors.size %]
|
||
[% LxERP.t8("No errors have occurred.") %]
|
||
[% ELSE %]
|
||
<table>
|
||
<tr class="listheader">
|
||
<th>[% LxERP.t8("Shop Order") %]</th>
|
||
<th>[% LxERP.t8("Error") %]</th>
|
||
<th>[% LxERP.t8("Part") %]</th>
|
||
<th>[% LxERP.t8("Partnumber") %]</th>
|
||
<th>[% LxERP.t8("Message") %]</th>
|
||
</tr>
|
||
|
||
[% FOREACH error = data.conversion_errors %]
|
||
[% FOREACH message = data.conversion %]
|
||
<tr>
|
||
<td valign="top">[% IF error.id %][% L.link(SELF.url_for(controller='ShopOrder', action='show', id=error.id), HTML.escape(error.number), target="_blank") %][% ELSE %]–[% END %]</td>
|
||
<td valign="top">[% HTML.escape(error.message) %]</td>
|
||
<td valign="top">[% HTML.escape(message.id) %]</td>
|
||
<td valign="top">[% HTML.escape(message.number) %]</td>
|
||
<td valign="top">[% HTML.escape(message.message) %]</td>
|
||
</tr>
|
||
[% END %]
|
||
</table>
|
||
[% END %]
|
||
</table>
|
||
</p>
|
Auch abrufbar als: Unified diff
Shopmodul: Artikel überarbeitet
Dinge aus Connector ausgelagert, die auch für andere Conectoren
gültigkeit haben
Output des Backgroundjob MassUpload überarbeitet
POD
Typo