Skip to content
Code-Schnipsel Gruppen Projekte
Commit e5583c58 erstellt von Henning Leutz's avatar Henning Leutz :martial_arts_uniform:
Dateien durchsuchen

refactor: invoice#66

Übergeordneter e7499f9c
Keine zugehörigen Branchen gefunden
Keine zugehörigen Tags gefunden
Keine zugehörigen Merge Requests gefunden
werden angezeigt mit 2965 Ergänzungen und 0 Löschungen
<?php
/**
* This file contains package_quiqqer_invoice_ajax_invoices_temporary_product_calc
*/
/**
* Calculates the current price of the article
*
* @return string
*/
QUI::$Ajax->registerFunction(
'package_quiqqer_erp_ajax_products_calc',
function ($params, $user) {
$params = \json_decode($params, true);
$user = \json_decode($user, true);
if (!empty($user)) {
try {
$User = QUI\ERP\User::convertUserDataToErpUser($user);
$Calc = QUI\ERP\Accounting\Calc::getInstance($User);
} catch (QUI\ERP\Exception $Exception) {
$Calc = QUI\ERP\Accounting\Calc::getInstance();
}
} else {
$Calc = QUI\ERP\Accounting\Calc::getInstance();
}
$Article = new QUI\ERP\Accounting\Article($params);
$Article->calc($Calc);
return $Article->toArray();
},
['params', 'user'],
'Permission::checkAdminUser'
);
<?php
/**
* This file contains package_quiqqer_erp_ajax_products_getProductEdit
*/
use QUI\ERP\Products\Controls\Products\ProductEdit;
use QUI\ERP\Products\Handler\Products;
/**
*
*/
QUI::$Ajax->registerFunction(
'package_quiqqer_erp_ajax_products_getProductEdit',
function ($productId, $user) {
$Product = Products::getProduct($productId);
$user = \json_encode($user, true);
$Control = new ProductEdit([
'Product' => $Product
]);
$css = ''; //QUI\Control\Manager::getCSS();
$html = $Control->create();
return $css.$html;
},
['productId', 'user'],
'Permission::checkAdminUser'
);
<?php
/**
* This file contains package_quiqqer_erp_ajax_products_hasProductCustomFields
*/
use QUI\ERP\Products\Handler\Products;
/**
*
*/
QUI::$Ajax->registerFunction(
'package_quiqqer_erp_ajax_products_hasProductCustomFields',
function ($productId) {
$Product = Products::getProduct($productId);
$fields = $Product->createUniqueProduct()->getCustomFields();
return \count($fields);
},
['productId'],
'Permission::checkAdminUser'
);
<?php
/**
* This file contains package_quiqqer_erp_ajax_products_parseProductToArticle
*/
use QUI\ERP\Products\Handler\Fields;
use QUI\ERP\Products\Handler\Products;
/**
*
*/
QUI::$Ajax->registerFunction(
'package_quiqqer_erp_ajax_products_parseProductToArticle',
function ($productId, $attributes, $user) {
$user = \json_decode($user, true);
$attributes = \json_decode($attributes, true);
$User = null;
$Locale = QUI::getLocale();
if (!empty($user)) {
try {
$User = QUI\ERP\User::convertUserDataToErpUser($user);
} catch (QUI\Exception $Exception) {
if (!isset($user['uid'])) {
throw $Exception;
}
$User = QUI::getUsers()->get($user['uid']);
}
$Locale = $User->getLocale();
}
try {
$Product = Products::getProduct((int)$productId);
foreach ($attributes as $field => $value) {
if (\strpos($field, 'field-') === false) {
continue;
}
$field = \str_replace('field-', '', $field);
$Field = $Product->getField((int)$field);
$Field->setValue($value);
}
// look if the invoice text field has values
try {
$Description = $Product->getField(Fields::FIELD_SHORT_DESC);
$InvoiceText = $Product->getField(
QUI\ERP\Accounting\Invoice\Handler::INVOICE_PRODUCT_TEXT_ID
);
if (!$InvoiceText->isEmpty()) {
$Description->setValue($InvoiceText->getValue());
}
} catch (QUI\Exception $Exception) {
QUI\System\Log::addNotice($Exception->getMessage());
}
// create unique product, to create the ERP Article, so invoice can work with it
$Unique = $Product->createUniqueProduct($User);
if (isset($attributes['quantity'])) {
$Unique->setQuantity($attributes['quantity']);
}
$Unique->calc();
return $Unique->toArticle($Locale)->toArray();
} catch (QUI\Exception $Exception) {
QUI\System\Log::write($Exception->getMessage());
}
return [];
},
['productId', 'attributes', 'user'],
'Permission::checkAdminUser'
);
<?php
/**
* This file contains package_quiqqer_erp_ajax_products_summary
*/
/**
* Data for the summary display of an article
* The calculation is with a brutto user, so you get the complete data
*
* @return array
*/
QUI::$Ajax->registerFunction(
'package_quiqqer_erp_ajax_products_summary',
function ($article) {
$article = \json_decode($article, true);
$Brutto = new QUI\ERP\User([
'id' => 'BRUTTO',
'country' => '',
'username' => '',
'firstname' => '',
'lastname' => '',
'lang' => QUI::getLocale()->getCurrent(),
'isCompany' => 0,
'isNetto' => 0
]);
$Brutto->setAttribute(
'quiqqer.erp.isNettoUser',
QUI\ERP\Utils\User::IS_BRUTTO_USER
);
$Calc = QUI\ERP\Accounting\Calc::getInstance($Brutto);
$Article = new QUI\ERP\Accounting\Article($article);
//$Article->setCurrency();
$Article->setUser($Brutto);
$Article->calc($Calc);
return $Article->toArray();
},
['article'],
'Permission::checkAdminUser'
);
.quiqqer-erp-sortableClone {
}
.quiqqer-erp-sortableClone-placeholder {
background: #fff;
color: #999;
cursor: pointer;
height: 100%;
position: absolute;
width: 100%;
}
.quiqqer-erp-backend-erpArticlePlaceholder-pos,
.quiqqer-erp-backend-erpArticlePlaceholder-articleNo,
.quiqqer-erp-backend-erpArticlePlaceholder-title,
.quiqqer-erp-backend-erpArticlePlaceholder-quantity,
.quiqqer-erp-backend-erpArticlePlaceholder-unitPrice,
.quiqqer-erp-backend-erpArticlePlaceholder-price {
float: left;
padding: 10px;
}
.quiqqer-erp-backend-erpArticlePlaceholder-pos {
width: 50px;
}
.quiqqer-erp-backend-erpArticlePlaceholder-articleNo,
.quiqqer-erp-backend-erpArticlePlaceholder-quantity,
.quiqqer-erp-backend-erpArticlePlaceholder-unitPrice,
.quiqqer-erp-backend-erpArticlePlaceholder-price {
width: 100px;
}
.quiqqer-erp-backend-erpArticlePlaceholder-title {
width: calc(100% - 800px);
}
.quiqqer-erp-backend-erpArticlePlaceholder-quantity,
.quiqqer-erp-backend-erpArticlePlaceholder-unitPrice,
.quiqqer-erp-backend-erpArticlePlaceholder-price {
text-align: right;
}
/*
---
script: Sortables.js
name: Sortables
description: Class for creating a drag and drop sorting interface for lists of items.
license: MIT-style license
authors:
- Tom Occhino
requires:
- Core/Fx.Morph
- Drag.Move
provides: [Sortables]
...
*/
define('package/quiqqer/erp/bin/backend/classes/Sortable', [
'css!package/quiqqer/erp/bin/backend/classes/Sortable.css'
], function () {
"use strict";
return new Class({
Implements: [Events, Options],
options: {
opacity : 1,
clone : false,
revert : false,
handle : false,
dragOptions : {},
unDraggableTags: ['button', 'input', 'a', 'textarea', 'select', 'option']
},
initialize: function (lists, options) {
this.setOptions(options);
this.elements = [];
this.lists = [];
this.idle = true;
this.addLists($$(document.id(lists) || lists));
if (!this.options.clone) {
this.options.revert = false;
}
if (this.options.revert) {
this.effect = new Fx.Morph(null, Object.merge({
duration: 250,
link : 'cancel'
}, this.options.revert));
}
},
/**
* @return {module:package/quiqqer/erp/bin/backend/classes/Sortable}
*/
attach: function () {
this.addLists(this.lists);
return this;
},
/**
* @return {module:package/quiqqer/erp/bin/backend/classes/Sortable}
*/
detach: function () {
this.lists = this.removeLists(this.lists);
return this;
},
/**
* @return {module:package/quiqqer/erp/bin/backend/classes/Sortable}
*/
addItems: function () {
Array.flatten(arguments).each(function (element) {
this.elements.push(element);
var start = element.retrieve('sortables:start', function (event) {
this.start.call(this, event, element);
}.bind(this));
(this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
}, this);
return this;
},
/**
* @return {module:package/quiqqer/erp/bin/backend/classes/Sortable}
*/
addLists: function () {
Array.flatten(arguments).each(function (list) {
this.lists.include(list);
this.addItems(list.getChildren());
}, this);
return this;
},
removeItems: function () {
return $$(Array.flatten(arguments).map(function (element) {
this.elements.erase(element);
var start = element.retrieve('sortables:start');
(this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
return element;
}, this));
},
removeLists: function () {
return $$(Array.flatten(arguments).map(function (list) {
this.lists.erase(list);
this.removeItems(list.getChildren());
return list;
}, this));
},
getDroppableCoordinates: function (element) {
var offsetParent = element.getOffsetParent();
var position = element.getPosition(offsetParent);
var scroll = {
w : window.getScroll(),
offsetParent: offsetParent.getScroll()
};
position.x += scroll.offsetParent.x;
position.y += scroll.offsetParent.y;
if (offsetParent.getStyle('position') === 'fixed') {
position.x -= scroll.w.x;
position.y -= scroll.w.y;
}
return position;
},
getClone: function (event, element) {
if (!this.options.clone) {
return new Element(element.tagName).inject(document.body);
}
if (typeOf(this.options.clone) === 'function') {
return this.options.clone.call(this, event, element, this.list);
}
var clone = element.clone(true).setStyles({
margin : 0,
position : 'absolute',
visibility: 'hidden',
width : element.getStyle('width')
}).addEvent('mousedown', function (event) {
element.fireEvent('mousedown', event);
});
//prevent the duplicated radio inputs from unchecking the real one
if (clone.get('html').test('radio')) {
clone.getElements('input[type=radio]').each(function (input, i) {
input.set('name', 'clone_' + i);
if (input.get('checked')) {
element.getElements('input[type=radio]')[i].set('checked', true);
}
});
}
return clone.inject(this.list).setPosition(this.getDroppableCoordinates(this.element));
},
getDroppables: function () {
var droppables = this.list.getChildren().erase(this.clone).erase(this.element);
if (!this.options.constrain) {
droppables.append(this.lists).erase(this.list);
}
return droppables;
},
insert: function (dragging, element) {
var where = 'inside';
if (this.lists.contains(element)) {
this.list = element;
this.drag.droppables = this.getDroppables();
} else {
where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
}
this.element.inject(element, where);
this.fireEvent('sort', [this.element, this.clone]);
},
start: function (event, element) {
if (!this.idle ||
event.rightClick ||
(!this.options.handle && this.options.unDraggableTags.contains(event.target.get('tag')))
) {
return;
}
this.idle = false;
this.element = element;
this.opacity = element.getStyle('opacity');
this.list = element.getParent();
this.clone = this.getClone(event, element);
this.drag = new Drag.Move(
this.clone, Object.merge({
droppables: this.getDroppables()
}, this.options.dragOptions)
).addEvents({
onSnap : function () {
event.stop();
this.clone.setStyle('visibility', 'visible');
this.element.setStyle('opacity', this.options.opacity || 0);
this.fireEvent('start', [this.element, this.clone]);
}.bind(this),
onEnter : this.insert.bind(this),
onCancel : this.end.bind(this),
onComplete: this.end.bind(this)
});
this.clone.inject(this.element, 'before');
this.drag.start(event);
},
end: function () {
this.drag.detach();
this.element.setStyle('opacity', this.opacity);
var self = this;
if (this.effect) {
var dim = this.element.getStyles('width', 'height'),
clone = this.clone,
pos = clone.computePosition(this.getDroppableCoordinates(clone));
var destroy = function () {
this.removeEvent('cancel', destroy);
clone.destroy();
self.reset();
};
this.effect.element = clone;
this.effect.start({
top : pos.top,
left : pos.left,
width : dim.width,
height : dim.height,
opacity: 0.25
}).addEvent('cancel', destroy).chain(destroy);
} else {
this.clone.destroy();
self.reset();
}
},
reset: function () {
this.idle = true;
this.fireEvent('complete', this.element);
},
/**
* @return {Array}
*/
serialize: function () {
var params = Array.link(arguments, {
modifier: Type.isFunction,
index : function (obj) {
return obj !== null;
}
});
var serial = this.lists.map(function (list) {
return list.getChildren().map(params.modifier || function (element) {
return element.get('id');
}, this);
}, this);
var index = params.index;
if (this.lists.length === 1) {
index = 0;
}
return (index || index === 0) && index >= 0 && index < this.lists.length ? serial[index] : serial;
}
});
});
.quiqqer-erp-backend-erpArticle {
align-items: stretch;
border-bottom: 1px solid #DEDEDE;
border-left: 2px solid #FFFFFF;
clear: both;
display: flex;
flex-direction: row;
float: left;
min-height: 50px;
position: relative;
width: 100%;
}
.quiqqer-erp-backend-erpArticle .cell-editable:focus {
box-shadow: 0 0 5px #2F8FC6;
}
.quiqqer-erp-backend-erpArticle-select {
border-left: 2px solid #2F8FC6;
}
.quiqqer-erp-backend-erpArticle .cell {
padding: 10px;
position: relative;
}
.quiqqer-erp-backend-erpArticle .cell-editable:hover {
background: rgba(0, 0, 0, 0.1);
cursor: pointer;
}
.quiqqer-erp-backend-erpArticle-pos {
width: 50px;
}
.quiqqer-erp-backend-erpArticle-text {
width: calc(100% - 800px);
}
.quiqqer-erp-backend-erpArticle-text-title {
clear: both;
font-weight: bold;
margin-bottom: 5px;
position: relative;
width: 100%;
}
.quiqqer-erp-backend-erpArticle-text-description {
clear: both;
position: relative;
width: 100%;
}
.quiqqer-erp-backend-erpArticle-text-description-edit {
background: #EFEFEF;
border: 1px solid #EFEFEF;
height: 100%;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
width: 100%
}
.quiqqer-erp-backend-erpArticle-text-description-buttons {
height: 50px;
text-align: center;
}
.quiqqer-erp-backend-erpArticle-quantity {
text-align: right;
width: 100px;
}
.quiqqer-erp-backend-erpArticle-articleNo,
.quiqqer-erp-backend-erpArticle-unitPrice,
.quiqqer-erp-backend-erpArticle-price,
.quiqqer-erp-backend-erpArticle-vat,
.quiqqer-erp-backend-erpArticle-discount,
.quiqqer-erp-backend-erpArticle-total {
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
width: 100px;
white-space: nowrap;
}
.quiqqer-erp-backend-erpArticle-articleNo {
text-align: left;
}
.quiqqer-erp-backend-erpArticle-total {
width: 150px;
}
.quiqqer-erp-backend-erpArticle-buttons {
background: #fff;
bottom: 0;
opacity: 0;
padding: 10px;
position: absolute;
right: 0;
text-align: right;
transition: opacity 0.2s;
width: 150px;
z-index: 10;
}
.quiqqer-erp-backend-erpArticle-buttons button {
padding: 0 5px;
line-height: 20px;
margin-left: 5px;
}
.quiqqer-erp-backend-erpArticle:hover .quiqqer-erp-backend-erpArticle-buttons {
opacity: 1;
transition: opacity 0.2s;
}
.quiqqer-erp-dialog-edit-article-description input {
margin-bottom: 10px;
width: 100%;
}
<div class="quiqqer-erp-backend-erpArticle-pos cell"></div>
<div class="quiqqer-erp-backend-erpArticle-articleNo cell cell-editable"></div>
<div class="quiqqer-erp-backend-erpArticle-text cell"></div>
<div class="quiqqer-erp-backend-erpArticle-quantity cell cell-editable"></div>
<div class="quiqqer-erp-backend-erpArticle-unitPrice cell cell-editable"></div>
<div class="quiqqer-erp-backend-erpArticle-price cell"></div>
<div class="quiqqer-erp-backend-erpArticle-vat cell cell-editable"></div>
<div class="quiqqer-erp-backend-erpArticle-discount cell cell-editable"></div>
<div class="quiqqer-erp-backend-erpArticle-total cell"></div>
<div class="quiqqer-erp-backend-erpArticle-buttons"></div>
Dieser Diff ist reduziert.
.quiqqer-erp-backend-erpItems {
display: block;
overflow: auto;
position: relative;
width: 100%;
}
.quiqqer-erp-backend-erpItems-container {
min-width: 1000px;
}
.quiqqer-erp-backend-erpItems-header {
background: #DEDEDE;
float: left;
margin-bottom: 5px;
width: 100%;
}
.quiqqer-erp-backend-erpItems-items {
display: inline-block;
height: calc(100% - 30px);
overflow: auto;
position: relative;
width: 100%;
}
.header-cell {
float: left;
padding: 5px 10px;
}
.quiqqer-erp-backend-erpItems-header-pos {
width: 50px;
}
.quiqqer-erp-backend-erpItems-header-description {
width: calc(100% - 800px);
}
.quiqqer-erp-backend-erpItems-header-quantity {
text-align: right;
width: 100px;
}
.quiqqer-erp-backend-erpItems-header-articleNo,
.quiqqer-erp-backend-erpItems-header-unitPrice,
.quiqqer-erp-backend-erpItems-header-price,
.quiqqer-erp-backend-erpItems-header-vat,
.quiqqer-erp-backend-erpItems-header-discount,
.quiqqer-erp-backend-erpItems-header-total {
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
width: 100px;
white-space: nowrap;
}
.quiqqer-erp-backend-erpItems-header-articleNo {
text-align: left;
}
.quiqqer-erp-backend-erpItems-header-total {
width: 150px;
}
<div class="quiqqer-erp-backend-erpItems-container">
<div class="quiqqer-erp-backend-erpItems-header">
<div class="quiqqer-erp-backend-erpItems-header-pos header-cell">
#
</div>
<div class="quiqqer-erp-backend-erpItems-header-articleNo header-cell">
{{titleArticleNo}}
</div>
<div class="quiqqer-erp-backend-erpItems-header-description header-cell">
{{titleDescription}}
</div>
<div class="quiqqer-erp-backend-erpItems-header-quantity header-cell">
{{titleQuantity}}
</div>
<div class="quiqqer-erp-backend-erpItems-header-unitPrice header-cell">
{{titleUnitPrice}}
</div>
<div class="quiqqer-erp-backend-erpItems-header-price header-cell">
{{titlePrice}}
</div>
<div class="quiqqer-erp-backend-erpItems-header-vat header-cell">
{{titleVAT}}
</div>
<div class="quiqqer-erp-backend-erpItems-header-discount header-cell">
{{titleDiscount}}
</div>
<div class="quiqqer-erp-backend-erpItems-header-total header-cell">
{{titleSum}}
</div>
</div>
<div class="quiqqer-erp-backend-erpItems-items"></div>
</div>
/**
* @module package/quiqqer/erp/bin/backend/controls/articles/ArticleList
* @author www.pcsg.de (Henning Leutz)
*
* Article list (Produkte Positionen)
*
* @event onCalc [self, {Object} calculation]
* @event onArticleSelect [self, {Object} Article]
* @event onArticleUnSelect [self, {Object} Article]
* @event onArticleReplaceClick [self, {Object} Article]
*/
define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
'qui/QUI',
'qui/controls/Control',
'Mustache',
'Ajax',
'Locale',
'package/quiqqer/erp/bin/backend/controls/articles/Article',
'package/quiqqer/erp/bin/backend/classes/Sortable',
'text!package/quiqqer/erp/bin/backend/controls/articles/ArticleList.html',
'text!package/quiqqer/erp/bin/backend/controls/articles/ArticleList.sortablePlaceholder.html',
'css!package/quiqqer/erp/bin/backend/controls/articles/ArticleList.css'
], function (QUI, QUIControl, Mustache, QUIAjax, QUILocale, Article, Sortables, template, templateSortablePlaceholder) {
"use strict";
var lg = 'quiqqer/erp';
return new Class({
Extends: QUIControl,
Type : 'package/quiqqer/erp/bin/backend/controls/articles/ArticleList',
Binds: [
'$onArticleDelete',
'$onArticleSelect',
'$onArticleUnSelect',
'$onArticleReplace',
'$calc',
'$onInject'
],
options: {
currency: false // bool || string -> EUR, USD ...
},
initialize: function (options) {
this.parent(options);
this.$articles = [];
this.$user = {};
this.$sorting = false;
this.$calculationTimer = null;
this.$calculations = {
currencyData: {},
isEuVat : 0,
isNetto : true,
nettoSubSum : 0,
nettoSum : 0,
subSum : 0,
sum : 0,
vatArray : [],
vatText : []
};
this.$Container = null;
this.$Sortables = null;
this.$priceFactors = [];
this.addEvents({
onInject: this.$onInject
});
},
/**
* Create the DOMNode element
*
* @returns {HTMLDivElement}
*/
create: function () {
this.$Elm = this.parent();
this.$Elm.addClass('quiqqer-erp-backend-erpItems');
this.$Elm.set({
html: Mustache.render(template, {
titleArticleNo : QUILocale.get(lg, 'products.articleNo'),
titleDescription: QUILocale.get(lg, 'products.description'),
titleQuantity : QUILocale.get(lg, 'products.quantity'),
titleUnitPrice : QUILocale.get(lg, 'products.unitPrice'),
titlePrice : QUILocale.get(lg, 'products.price'),
titleVAT : QUILocale.get(lg, 'products.table.vat'),
titleDiscount : QUILocale.get(lg, 'products.discount'),
titleSum : QUILocale.get(lg, 'products.sum')
})
});
if (this.getAttribute('styles')) {
this.setStyles(this.getAttribute('styles'));
}
this.$Container = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-items');
return this.$Elm;
},
/**
* event: on inject
*/
$onInject: function () {
(function () {
if (this.$articles.length) {
this.$articles[0].select();
}
}).delay(500, this);
},
/**
* Serialize the list
*
* @returns {Object}
*/
serialize: function () {
var articles = this.$articles.map(function (Article) {
var attr = Article.getAttributes();
attr.control = typeOf(Article);
return attr;
});
return {
articles : articles,
priceFactors: this.$priceFactors
};
},
/**
* Unserialize the list
*
* load the serialized list into
* current articles would be deleted
*
* @param {Object|String} list
* @return {Promise}
*/
unserialize: function (list) {
var self = this,
data = {};
if (typeOf(list) === 'string') {
try {
data = JSON.stringify(list);
} catch (e) {
}
} else {
data = list;
}
if ("priceFactors" in data) {
this.$priceFactors = data.priceFactors;
}
if (!("articles" in data)) {
return Promise.resolve();
}
this.$articles = [];
var controls = data.articles.map(function (Article) {
if (typeof Article.control !== 'undefined' && Article.control !== '') {
return Article.control;
}
return 'package/quiqqer/erp/bin/backend/controls/articles/Article';
}).unique();
require(controls, function () {
var i, len, article, index;
for (i = 0, len = data.articles.length; i < len; i++) {
article = data.articles[i];
index = controls.indexOf(article.control);
if (index === -1) {
self.addArticle(new Article(article));
continue;
}
try {
self.addArticle(new arguments[index](article));
} catch (e) {
console.log(e);
}
}
});
},
/**
* Set user details to the list
*
* @param {Object} user
*/
setUser: function (user) {
this.$user = user;
this.$articles.each(function (Article) {
Article.setUser(this.$user);
}.bind(this));
},
/**
* Return the user details
*
* @return {Object|*|{}}
*/
getUser: function () {
return this.$user;
},
/**
* Add a product to the list
* The product must be an instance of Article
*
* @param {Object} Child
*/
addArticle: function (Child) {
if (typeof Child !== 'object') {
return;
}
if (!(Child instanceof Article)) {
return;
}
if (this.getAttribute('currency')) {
Child.setCurrency(this.getAttribute('currency'));
}
this.$articles.push(Child);
Child.setUser(this.$user);
Child.setPosition(this.$articles.length);
Child.addEvents({
onDelete : this.$onArticleDelete,
onSelect : this.$onArticleSelect,
onUnSelect: this.$onArticleUnSelect,
onReplace : this.$onArticleReplace,
onCalc : this.$calc
});
if (this.$Container) {
Child.inject(this.$Container);
}
Child.getElm().addClass('article');
},
/**
* Replace an article with another
*
* @param {Object} NewArticle
* @param {Number} position
*/
replaceArticle: function (NewArticle, position) {
if (typeof NewArticle !== 'object') {
return;
}
if (!(NewArticle instanceof Article)) {
return;
}
var Wanted = this.$articles.find(function (Article) {
return Article.getAttribute('position') === position;
});
this.addArticle(NewArticle);
if (Wanted) {
NewArticle.getElm().inject(Wanted.getElm(), 'after');
Wanted.remove();
}
NewArticle.setPosition(position);
this.$recalculatePositions();
return this.$calc();
},
/**
* Insert a new empty product
*/
insertNewProduct: function () {
this.addArticle(new Article());
},
/**
* Return the articles as an array
*
* @return {Array}
*/
save: function () {
return this.$articles.map(function (Article) {
return Object.merge(Article.getAttributes(), {
control: Article.getType()
});
});
},
/**
* Calculate the list
*/
$calc: function () {
if (this.$calculationTimer) {
clearTimeout(this.$calculationTimer);
this.$calculationTimer = null;
}
var self = this;
this.$calculationTimer = (function () {
self.$executeCalculation();
}).delay(500);
},
/**
* Calc
*/
/**
* Execute a new calculation
*
* @returns {Promise}
*/
$executeCalculation: function () {
var self = this;
return new Promise(function (resolve) {
var articles = self.$articles.map(function (Article) {
return Article.getAttributes();
});
QUIAjax.get('package_quiqqer_erp_ajax_products_calc', function (result) {
self.$calculations = result;
self.fireEvent('calc', [self, result]);
resolve(result);
}, {
'package': 'quiqqer/erp',
articles : JSON.encode(articles),
user : JSON.encode(self.$user)
});
});
},
/**
* Return the current calculations
*
* @returns {{currencyData: {}, isEuVat: number, isNetto: boolean, nettoSubSum: number, nettoSum: number, subSum: number, sum: number, vatArray: Array, vatText: Array}|*}
*/
getCalculation: function () {
return this.$calculations;
},
/**
* Return price factors
*
* @return {[]}
*/
getPriceFactors: function () {
return this.$priceFactors;
},
/**
* Remove a price factor
*
* @param no
*/
removePriceFactor: function (no) {
var newList = [];
for (var i = 0, len = this.$priceFactors.length; i < len; i++) {
if (i !== parseInt(no)) {
newList.push(this.$priceFactors[i]);
}
}
this.$priceFactors = newList;
},
/**
* Sorting
*/
/**
* Toggles the sorting
*/
toggleSorting: function () {
if (this.$sorting) {
this.disableSorting();
return;
}
this.enableSorting();
},
/**
* Enables the sorting
* Articles can be sorted by drag and drop
*/
enableSorting: function () {
var self = this;
var Elm = this.getElm(),
elements = Elm.getElements('.article');
elements.each(function (Node) {
var Article = QUI.Controls.getById(Node.get('data-quiid'));
var attributes = Article.getAttributes();
Article.addEvents({
onSetPosition: self.$onArticleSetPosition
});
new Element('div', {
'class': 'quiqqer-erp-sortableClone-placeholder',
html : Mustache.render(templateSortablePlaceholder, attributes)
}).inject(Node);
});
this.$Sortables = new Sortables(this.$Container, {
revert: {
duration : 500,
transition: 'elastic:out'
},
clone: function (event) {
var Target = event.target;
if (!Target.hasClass('article')) {
Target = Target.getParent('.article');
}
var size = Target.getSize(),
pos = Target.getPosition(self.$Container);
return new Element('div', {
styles: {
background: 'rgba(0,0,0,0.5)',
height : size.y,
position : 'absolute',
top : pos.y,
width : size.x,
zIndex : 1000
}
});
},
onStart: function (element) {
element.addClass('quiqqer-erp-sortableClone');
self.$Container.setStyles({
height : self.$Container.getSize().y,
overflow: 'hidden',
width : self.$Container.getSize().x
});
},
onComplete: function (element) {
element.removeClass('quiqqer-erp-sortableClone');
self.$Container.setStyles({
height : null,
overflow: null,
width : null
});
self.$recalculatePositions();
}
});
this.$sorting = true;
},
/**
* Disables the sorting
* Articles can not be sorted
*/
disableSorting: function () {
this.$sorting = false;
var self = this,
Elm = this.getElm(),
elements = Elm.getElements('.article');
Elm.getElements('.quiqqer-erp-sortableClone-placeholder').destroy();
elements.each(function (Node) {
var Article = QUI.Controls.getById(Node.get('data-quiid'));
Article.removeEvents({
onSetPosition: self.$onArticleSetPosition
});
});
this.$Sortables.detach();
this.$Sortables = null;
this.$articles.sort(function (A, B) {
return A.getAttribute('position') - B.getAttribute('position');
});
},
/**
* Is the sorting enabled?
*
* @return {boolean}
*/
isSortingEnabled: function () {
return this.$sorting;
},
/**
* event: on set position at article
*
* @param Article
*/
$onArticleSetPosition: function (Article) {
Article.getElm()
.getElement('.quiqqer-erp-backend-erpArticlePlaceholder-pos')
.set('html', Article.getAttribute('position'));
},
/**
* Recalculate the Position of all Articles
*/
$recalculatePositions: function () {
var i, len, Article;
var Elm = this.getElm(),
elements = Elm.getElements('.article');
for (i = 0, len = elements.length; i < len; i++) {
Article = QUI.Controls.getById(elements[i].get('data-quiid'));
Article.setPosition(i + 1);
}
},
/**
* Events
*/
/**
* event : on article delete
*
* @param {Object} Article
*/
$onArticleDelete: function (Article) {
if (this.$selectedArticle) {
this.$selectedArticle.unselect();
}
var i, len, Current;
var self = this,
articles = [],
position = 1;
for (i = 0, len = this.$articles.length; i < len; i++) {
if (this.$articles[i].getAttribute('position') === Article.getAttribute('position')) {
continue;
}
Current = this.$articles[i];
Current.setPosition(position);
articles.push(Current);
position++;
}
this.$articles = articles;
this.$executeCalculation().then(function () {
if (self.$articles.length) {
self.$articles[0].select();
}
});
},
/**
* event : on article delete
*
* @param {Object} Article
*/
$onArticleSelect: function (Article) {
if (this.$selectedArticle &&
this.$selectedArticle !== Article) {
this.$selectedArticle.unselect();
}
this.$selectedArticle = Article;
this.fireEvent('articleSelect', [this, this.$selectedArticle]);
},
/**
* event : on article delete
*
* @param Article
*/
$onArticleUnSelect: function (Article) {
if (this.$selectedArticle === Article) {
this.$selectedArticle = null;
this.fireEvent('articleUnSelect', [this, this.$selectedArticle]);
}
},
/**
* event : on article replace click
*
* @param Article
*/
$onArticleReplace: function (Article) {
this.fireEvent('articleReplaceClick', [this, Article]);
},
/**
* Return the current selected Article
*
* @returns {null|Object}
*/
getSelectedArticle: function () {
return this.$selectedArticle;
}
});
});
<div class="quiqqer-erp-backend-erpArticlePlaceholder-pos">{{position}}</div>
<div class="quiqqer-erp-backend-erpArticlePlaceholder-articleNo">{{articleNo}}</div>
<div class="quiqqer-erp-backend-erpArticlePlaceholder-title">{{title}}</div>
<div class="quiqqer-erp-backend-erpArticlePlaceholder-quantity">{{quantity}}</div>
<div class="quiqqer-erp-backend-erpArticlePlaceholder-unitPrice">{{unitPrice}}</div>
<div class="quiqqer-erp-backend-erpArticlePlaceholder-price">{{price}}</div>
.quiqqer-erp-backend-erpArticleText {
align-items: stretch;
border-bottom: 1px solid #DEDEDE;
border-left: 2px solid #FFFFFF;
clear: both;
display: flex;
flex-direction: row;
float: left;
min-height: 50px;
position: relative;
width: 100%;
}
.quiqqer-erp-backend-erpArticle-select {
border-left: 2px solid #2F8FC6;
}
.quiqqer-erp-backend-erpArticleText .cell {
padding: 10px;
position: relative;
}
.quiqqer-erp-backend-erpArticleText .cell-editable:hover {
background: rgba(0, 0, 0, 0.1);
cursor: pointer;
}
.quiqqer-erp-backend-erpArticleText-pos {
width: 50px;
}
.quiqqer-erp-backend-erpArticleText-text {
width: calc(100% - 250px);
}
.quiqqer-erp-backend-erpArticleText-text-title {
clear: both;
font-weight: bold;
margin-bottom: 5px;
position: relative;
width: 100%;
}
.quiqqer-erp-backend-erpArticleText-text-description {
clear: both;
position: relative;
width: 100%;
}
.quiqqer-erp-backend-erpArticleText-text-description-edit {
background: #EFEFEF;
border: 1px solid #EFEFEF;
height: 100%;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
width: 100%
}
.quiqqer-erp-backend-erpArticleText-text-description-buttons {
height: 50px;
text-align: center;
}
.quiqqer-erp-backend-erpArticleText-buttons {
background: #fff;
bottom: 0;
opacity: 0;
padding: 10px;
position: absolute;
right: 0;
text-align: right;
transition: opacity 0.2s;
width: 150px;
z-index: 10;
}
.quiqqer-erp-backend-erpArticleText-buttons button {
padding: 0 5px;
line-height: 20px;
margin-left: 5px;
}
.quiqqer-erp-backend-erpArticleText:hover .quiqqer-erp-backend-erpArticleText-buttons {
opacity: 1;
transition: opacity 0.2s;
}
<div class="quiqqer-erp-backend-erpArticleText-pos cell"></div>
<div class="quiqqer-erp-backend-erpArticleText-text cell"></div>
<div class="quiqqer-erp-backend-erpArticleText-buttons"></div>
/**
* @module package/quiqqer/erp/bin/backend/controls/articles/Text
* @author www.pcsg.de (Henning Leutz)
*
* Text Produkt
* - Dieses "Produkt" benhaltet nur text und hat keine Summe oder Preise
* - Dieses Produkt wird verwendet für Hinweise auf der Rechnung
*/
define('package/quiqqer/erp/bin/backend/controls/articles/Text', [
'package/quiqqer/erp/bin/backend/controls/articles/Article',
'qui/controls/buttons/Button',
'Locale',
'Mustache',
'text!package/quiqqer/erp/bin/backend/controls/articles/Text.html',
'css!package/quiqqer/erp/bin/backend/controls/articles/Text.css'
], function (Article, QUIButton, QUILocale, Mustache, template) {
"use strict";
var lg = 'quiqqer/Article';
return new Class({
Extends: Article,
Type : 'package/quiqqer/Article/bin/backend/controls/articles/Text',
Binds: [
'$onEditTitle',
'$onEditDescription'
],
initialize: function (options) {
this.parent(options);
this.setAttributes({
'class': 'QUI\\ERP\\Accounting\\Invoice\\Articles\\Text'
});
},
/**
* Create the DOMNode element
*
* @returns {HTMLDivElement}
*/
create: function () {
this.$Elm = new Element('div');
this.$Elm.addClass('quiqqer-erp-backend-erpArticleText');
this.$Elm.set({
html : Mustache.render(template),
events: {
click: this.select
}
});
this.$Position = this.$Elm.getElement('.quiqqer-erp-backend-erpArticleText-pos');
this.$Text = this.$Elm.getElement('.quiqqer-erp-backend-erpArticleText-text');
this.$Buttons = this.$Elm.getElement('.quiqqer-erp-backend-erpArticleText-buttons');
this.$Loader = new Element('div', {
html : '<span class="fa fa-spinner fa-spin"></span>',
styles: {
background: '#fff',
display : 'none',
left : 0,
padding : 10,
position : 'absolute',
top : 0,
width : '100%'
}
}).inject(this.$Position);
new Element('span').inject(this.$Position);
if (this.getAttribute('position')) {
this.setPosition(this.getAttribute('position'));
}
// text nodes
this.$Title = new Element('div', {
'class': 'quiqqer-erp-backend-erpArticleText-text-title cell-editable'
}).inject(this.$Text);
this.$Description = new Element('div', {
'class': 'quiqqer-erp-backend-erpArticleText-text-description cell-editable'
}).inject(this.$Text);
this.$Title.addEvent('click', this.$onEditTitle);
this.$Description.addEvent('click', this.$onEditDescription);
this.setTitle(this.getAttribute('title'));
this.setDescription(this.getAttribute('description'));
// edit buttons
new QUIButton({
title : QUILocale.get(lg, 'erp.articleList.article.button.replace'),
icon : 'fa fa-retweet',
styles: {
'float': 'none'
},
events: {
onClick: this.$onReplaceClick
}
}).inject(this.$Buttons);
new QUIButton({
title : QUILocale.get(lg, 'erp.articleList.article.button.delete'),
icon : 'fa fa-trash',
styles: {
'float': 'none'
},
events: {
onClick: this.openDeleteDialog
}
}).inject(this.$Buttons);
this.$created = true;
return this.$Elm;
},
/**
* Calculates nothing
* Text Article has no prices
*
* @return {Promise}
*/
calc: function () {
return Promise.resolve();
},
/**
* Set the product title
*
* @param {String} title
*/
setTitle: function (title) {
this.setAttribute('title', title);
this.$Title.set('html', title);
if (title === '') {
this.$Title.set('html', '&nbsp;');
}
},
/**
* Set the product description
*
* @param {String} description
*/
setDescription: function (description) {
this.setAttribute('description', description);
this.$Description.set('html', description);
if (description === '') {
this.$Description.set('html', '&nbsp;');
}
},
/**
* Set the product quantity
*
* @return {Promise}
*/
setQuantity: function () {
return Promise.resolve();
},
/**
* Set the product unit price
*
*/
setUnitPrice: function () {
return Promise.resolve();
},
/**
* Set the product unit price
**/
setVat: function () {
return Promise.resolve();
},
/**
* Show the loader
*/
showLoader: function () {
this.$Loader.setStyle('display', null);
},
/**
* Hide the loader
*/
hideLoader: function () {
this.$Loader.setStyle('display', 'none');
}
});
});
<form>
<table class="data-table data-table-flexbox">
<tbody>
<tr>
<td>
<label class="field-container">
<span class="field-container-item">Menge</span>
<input type="number" class="field-container-field" name="quantity" value="1"/>
</label>
</td>
</tr>
</tbody>
</table>
</form>
\ No newline at end of file
.quiqqer-invoice-addProductWin .quiqqer-products-productEdit-header-title {
font-size: 20px;
font-weight: bold;
padding-bottom: 10px;
}
.quiqqer-invoice-addProductWin .quiqqer-products-productEdit-header-text {
padding-bottom: 20px;
}
\ No newline at end of file
/**
* @module package/quiqqer/erp/bin/backend/controls/articles/product/AddProductWindow
* @author www.pcsg.de (Henning Leutz)
*/
define('package/quiqqer/erp/bin/backend/controls/articles/product/AddProductWindow', [
'qui/QUI',
'qui/controls/Control',
'qui/controls/windows/Confirm',
'qui/utils/Form',
'package/quiqqer/productsearch/bin/controls/products/search/Window',
'Ajax',
'Mustache',
'text!package/quiqqer/erp/bin/backend/controls/articles/product/AddProductWindow.ProductSettings.html',
'css!package/quiqqer/erp/bin/backend/controls/articles/product/AddProductWindow.css'
], function (QUI, QUIControl, QUIConfirm, QUIFormUtils, ProductSearch, QUIAjax, Mustache,
templateProductSettings) {
"use strict";
return new Class({
Extends: QUIControl,
Type : 'package/quiqqer/erp/bin/backend/controls/articles/product/AddProductWindow',
options: {
user: false
},
initialize: function (options) {
this.parent(options);
this.$user = {};
if (typeof options.user !== 'undefined') {
this.$user = options.user;
}
},
/**
* open and start the product selection
*/
open: function () {
var self = this;
new ProductSearch({
autoclose: false,
events : {
onSubmit: function (Win, products) {
var productId = products[0];
Win.Loader.show();
self.$hasProductCustomFields(productId).then(function (hasCustomFields) {
return Win.close().then(function () {
if (!hasCustomFields) {
return Promise.resolve(false);
}
return self.openProductSettings(productId);
});
}).then(function (productSettings) {
return self.$parseProductToArticle(productId, productSettings);
}).then(function (article) {
self.fireEvent('submit', [self, article]);
}).catch(function (err) {
console.error(err);
});
}
}
}).open();
},
/**
* Opens the product settings for a product
*
* @param productId
* @returns {Promise}
*/
openProductSettings: function (productId) {
var self = this;
return new Promise(function (resolve) {
new QUIConfirm({
title : 'Produkt Eigenschaften', // #locale
icon : 'fa fa-shopping-bag',
maxHeight: 500,
maxWidth : 500,
events : {
onOpen: function (Win) {
Win.Loader.show();
var Content = Win.getContent();
Content.set('html', Mustache.render(templateProductSettings));
Content.addClass('quiqqer-erp-addProductWin');
var Form = Content.getElement('form');
var Table = Form.getElement('table tbody');
var Row = new Element('tr', {
html: '<td><label class="field-container"></label></td>'
});
self.$getProductEdit(productId).then(function (result) {
var Ghost = new Element('div', {
html: result
});
var Header = Ghost.getElement('header');
if (Header) {
Header.getElements('.quiqqer-products-productEdit-header-image').destroy();
Header.inject(Form, 'top');
}
Ghost.getElements('.quiqqer-product-field').each(function (Field) {
var RowClone = Row.clone();
var Label = RowClone.getElement('label');
Label.set('html', Field.get('html'));
Label.getElement('.quiqqer-product-field-title')
.addClass('field-container-item');
var Value = Label.getElement('.quiqqer-product-field-value');
var Input = Value.getElement('input,select');
if (Input) {
Input.replaces(Value);
Input.addClass('field-container-field');
} else {
Label.getElement('.quiqqer-product-field-value')
.addClass('field-container-field');
}
RowClone.inject(Table);
});
QUI.parse(Form).then(function () {
return Win.Loader.hide();
});
}).catch(function (err) {
console.error(err);
});
},
onSubmit: function (Win) {
var Form = Win.getContent().getElement('form');
var data = QUIFormUtils.getFormData(Form);
resolve(data);
},
onCancel: function () {
resolve(false);
}
}
}).open();
});
},
/**
* Return the user data
*
* @returns {{}|*}
*/
getUserData: function () {
return this.$user;
},
/**
* Return the data of a product for an ERP article
*
* @param {String|Number} productId
* @param {Object} [attributes] - fields, quantity and so on
* @returns {Promise}
*/
$parseProductToArticle: function (productId, attributes) {
var self = this;
attributes = attributes || {};
return new Promise(function (resolve, reject) {
QUIAjax.get('package_quiqqer_erp_ajax_products_parseProductToArticle', resolve, {
'package' : 'quiqqer/erp',
productId : productId,
attributes: JSON.encode(attributes),
user : JSON.encode(self.getUserData()),
onError : reject
});
});
},
/**
* Return the product edit
*
* @param {String|Number} productId
* @returns {Promise}
*/
$getProductEdit: function (productId) {
return new Promise(function (resolve, reject) {
QUIAjax.get('package_quiqqer_erp_ajax_products_getProductEdit', resolve, {
'package': 'quiqqer/erp',
productId: productId,
user : JSON.encode(this.getUserData()),
onError : reject
});
}.bind(this));
},
/**
* Has the product custom fields
*
* @param productId
* @returns {Promise}
*/
$hasProductCustomFields: function (productId) {
return new Promise(function (resolve, reject) {
QUIAjax.get('package_quiqqer_erp_ajax_products_hasProductCustomFields', resolve, {
'package': 'quiqqer/erp',
productId: productId,
onError : reject
});
}.bind(this));
}
});
});
0% Lade oder .
You are about to add 0 people to the discussion. Proceed with caution.
Bearbeitung dieser Nachricht zuerst beenden!
Bitte registrieren oder zum Kommentieren