Partner Producthchange WIP 2024-07-23

This commit is contained in:
Frank Schubert
2024-07-24 13:34:39 +02:00
parent ce671f2edd
commit a4f6b3b98c
8 changed files with 784 additions and 303 deletions

View File

@@ -1,3 +1,7 @@
<?php
$f = false;
$hide_credit = false;
?>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<!-- start page title -->
@@ -12,7 +16,7 @@
<li class="breadcrumb-item"><a
href="<?=self::getUrl("Contract", "view", ['id' => $contract->id])?>"><?=$contract->product_name?>
[<?=$contract->matchcode?>]</a></li>
<li class="breadcrumb-item active">Product-/Standortwechsel</li>
<li class="breadcrumb-item active">Produkt-/Standortwechsel</li>
</ol>
</div>
<h4 class="page-title">Aktives Produkt</h4>
@@ -77,246 +81,7 @@
</div>
<div class="card border-top-purple">
<div class="card-body">
<h4 class="text-center mb-3">Neuer Contract</h4>
<form method="post" action="<?=self::getUrl("Contract", "saveProductchange")?>">
<input type="hidden" name="contract_id" value="<?=$contract->id?>"/>
<div class="row justify-content-center">
<div class="col-xl-10">
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="product_id">Produkt</label>
<div class="col-lg-10">
<select class="form-control basicAutoComplete" autocomplete="off"
name="product_id" id="product_id"
data-url="<?=self::getUrl('Product', 'api')?>?do=findProduct&autocomplete=1"
placeholder="Tippen zum suchen..."
data-noresults-text="Keine Suchergebnisse">
<option></option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="matchcode">Matchcode:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="matchcode" id="matchcode"
value="<?=$contract->matchcode?>">
<small class="font-italic">Eindeutige Identifizierung das Produkts. Z.B.
Anschlussadresse, Domainname usw.</small>
</div>
</div>
<?php if(
(is_array($contract->product->attributes) && count($contract->product->attributes))
&& (array_key_exists(TT_ATTRIB_TERMINATION_REQUIRED_NAME, $contract->product->attributes)
&& $contract->product->attributes[TT_ATTRIB_TERMINATION_REQUIRED_NAME]->value == 1)
|| $contract->termination_id
): ?>
<div class="form-group row" id="termination_id-line">
<?php else: ?>
<div class="form-group row hidden" id="termination_id-line">
<?php endif; ?>
<label class="col-lg-2 col-form-label" for="matchcode">Anschluss</label>
<div class="col-lg-10">
<select name="termination_id" id="termination_id"
class="form-control select2">
<option></option>
<?php foreach($terminations as $t): ?>
<option value="<?=$t->id?>" <?=($t->id == $contract->termination_id) ? "selected='selected'" : ""?>><?=$t->code?>
- <?=$t->getAddress(true)?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="product_name">Individueller
Produktname:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="product_name"
id="product_name" value="<?=$contract->product_name?>">
<small class="font-italic">Scheint statt dem echten Produktnamen auf der
Rechnung auf</small>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="product_info">Produkt
Zusatztext:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="product_info"
id="product_info" value="<?=$contract->product_info?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="price_setup">Preis Setup:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price_setup" id="price_setup"
value="<?=$contract->price_setup?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="price">Preis Periodisch:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price" id="price"
value="<?=$contract->price?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="price_nne">Preis NNE</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price_nne" id="price_nne"
value="<?=$contract->price_nne?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="price_nbe">Preis NBE</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price_nbe" id="price_nbe"
value="<?=$contract->price_nbe?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label"
for="billing_period">Verrechnungsperiode</label>
<div class="col-lg-10">
<select class="form-control" name="billing_period" id="billing_period"
placeholder="Verrechnungsperiode">
<option value="1" <?=($product->billing_period == 1) ? "selected='selected'" : ""?>>
Monatlich
</option>
<option value="12" <?=($product->billing_period == 12) ? "selected='selected'" : ""?>>
Jährlich
</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="billing_delay">Verzögerter
Verrechnungsstart</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="billing_delay"
id="billing_delay" placeholder="Freimonate"
value="<?=$contract->billing_delay?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="billing_delay">Fertigstellungsdatum</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="finish_date" id="finish_date" value="">
</div>
</div>
<?php if((is_array($contract->linkFrom) && count($contract->linkFrom)) || (is_array($contract->linkTo) && count($contract->linkTo))): ?>
<h4>Verknüpfte Verträge</h4>
<table class="table table-striped table-sm table-bordered table-hover"
id="link-table">
<tr>
<th title="Verlinkten Contract mit neuem Contract verknüpfen">
Übernehmen
</th>
<th title="Verlinkten Contract mit altem Contract zusammen kündigen">
Kündigen
</th>
<th>Kü.Datum</th>
<th>Kunde</th>
<th>Contract ID</th>
<th>Produkt</th>
<th>Matchcode</th>
<th>Bestelldatum</th>
<th>Fertigstellung</th>
<th>Kündigung</th>
</tr>
<?php foreach($contract->linksWithCredit as $link): ?>
<?php
if($link->contract_id == $contract->id) {
$linkcontract = $link->origin;
} else {
$linkcontract = $link->contract;
}
if($linkcontract->isCancelled()) continue;
?>
<tr data-link-type="<?=$link->type?>">
<td>
<input type="radio" class="form-check link-keep"
id="link-<?=$link->id?>-action-keep"
name="links[<?=$link->id?>][action]"
value="keep" <?=($linkcontract->cancel_date && $linkcontract->cancel_date < date('U')) ? "" : "checked='checked'"?>
onchange="linkActionChange(<?=$link->id?>)" />
<?php if($link->type == "credit"): ?>
(Gutschrift wird neu erstellt)
<?php endif; ?>
</td>
<td>
<input type="radio" class="form-check link-cancel"
id="link-<?=$link->id?>-action-cancel"
name="links[<?=$link->id?>][action]" value="cancel"
onchange="linkActionChange(<?=$link->id?>)" />
</td>
<td>
<input type="text" class="form-control hidden" id="link-<?=$link->id?>-cancel_date" name="links[<?=$link->id?>][cancel_date]" value="<?=$linkcontract->getRegularCanceldate()?>" />
</td>
<td>
<a href="<?=self::getUrl("Address", "View", ["id" => $linkcontract->owner_id])?>" target="_blank"><?=$linkcontract->owner->getCompanyOrName()?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>">
<a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>" target="_blank"><?=$linkcontract->id?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>">
<a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>" target="_blank"><?=$linkcontract->product_name?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>">
<a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>" target="_blank"><?=$linkcontract->matchcode?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->order_date) ? date('d.m.Y', $linkcontract->order_date) : ""?></td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->finish_date) ? date('d.m.Y', $linkcontract->finish_date) : ""?></td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->cancel_date) ? date('d.m.Y', $linkcontract->cancel_date) : ""?></td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
<!-- TODO: Fileupload -->
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="note">Interne Notiz</label>
<div class="col-lg-10">
<textarea id="note" class="form-control" name="note"
rows="5"><?=$contract->note?></textarea>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col text-center">
<input type="submit" class="btn btn-purple" value="Produktwechsel speichern"/>
</div>
</div>
</form>
</div>
</div>
<?php include(realpath(dirname(__FILE__))."/include/productchange-action.php"); ?>
<div class="card">
@@ -435,7 +200,7 @@
function linkActionChange(link_id) {
//console.log($("#link-" + link_id + "-action-cancel").prop("checked"));
if($("#link-" + link_id + "-action-cancel").prop("checked")) {
if($("#link-" + link_id + "-action-cancel").prop("checked") && $("#finish_date").val()) {
$("#link-" + link_id + "-cancel_date").show();
} else {
$("#link-" + link_id + "-cancel_date").hide();

View File

@@ -0,0 +1,359 @@
<div class="card border-top-purple">
<div class="card-body">
<h4 class="text-center mb-3">Neuer Contract</h4>
<form method="post" action="<?=self::getUrl("Contract", "saveProductchange")?>">
<input type="hidden" name="contract_id" value="<?=$contract->id?>"/>
<?php if($f): ?>
<input type="hidden" name="f" value="<?=$f?>" />
<?php endif; ?>
<div class="row justify-content-center">
<div class="col-xl-10">
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="product_id">Produkt *</label>
<div class="col-lg-10">
<select class="form-control basicAutoComplete" autocomplete="off"
name="product_id" id="product_id"
data-url="<?=self::getUrl('Product', 'api')?>?do=findProduct&autocomplete=1"
placeholder="Tippen zum suchen..."
data-noresults-text="Keine Suchergebnisse">
<option></option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="matchcode">Matchcode:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="matchcode" id="matchcode"
value="<?=$contract->matchcode?>">
<small class="font-italic">Eindeutige Identifizierung das Produkts. Z.B.
Anschlussadresse, Domainname usw.</small>
</div>
</div>
<?php if(
(is_array($contract->product->attributes) && count($contract->product->attributes))
&& (array_key_exists(TT_ATTRIB_TERMINATION_REQUIRED_NAME, $contract->product->attributes)
&& $contract->product->attributes[TT_ATTRIB_TERMINATION_REQUIRED_NAME]->value == 1)
|| $contract->termination_id
): ?>
<div class="form-group row" id="termination_id-line">
<?php else: ?>
<div class="form-group row hidden" id="termination_id-line">
<?php endif; ?>
<label class="col-lg-2 col-form-label" for="matchcode">Anschluss *</label>
<div class="col-lg-10">
<select name="termination_id" id="termination_id"
class="form-control select2">
<option></option>
<?php foreach($terminations as $t): ?>
<option value="<?=$t->id?>" <?=($t->id == $contract->termination_id) ? "selected='selected'" : ""?>><?=$t->code?>
- <?=$t->getAddress(true)?></option>
<?php endforeach; ?>
</select>
<small>Anschluss nicht gefunden? <a href="<?=self::getUrl("Building")?>" target="_blank">Bitte anlegen</a></small>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="product_name">Individueller
Produktname:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="product_name"
id="product_name" value="<?=$contract->product_name?>">
<small class="font-italic">Scheint statt dem echten Produktnamen auf der
Rechnung auf</small>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="product_info">Produkt
Zusatztext:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="product_info"
id="product_info" value="<?=$contract->product_info?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="price_setup">Preis Setup:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price_setup" id="price_setup"
value="<?=$contract->price_setup?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="price">Preis Periodisch:</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price" id="price"
value="<?=$contract->price?>">
</div>
</div>
<div class="form-group row <?=$me->isAdmin() ? "" : "hidden"?>">
<label class="col-lg-2 col-form-label" for="price_nne">Preis NNE</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price_nne" id="price_nne"
value="<?=$contract->price_nne?>">
</div>
</div>
<div class="form-group row <?=$me->isAdmin() ? "" : "hidden"?>">
<label class="col-lg-2 col-form-label" for="price_nbe">Preis NBE</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="price_nbe" id="price_nbe"
value="<?=$contract->price_nbe?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label"
for="billing_period">Verrechnungsperiode *</label>
<div class="col-lg-10">
<select class="form-control" name="billing_period" id="billing_period"
placeholder="Verrechnungsperiode">
<option value="1" <?=($product->billing_period == 1) ? "selected='selected'" : ""?>>
Monatlich
</option>
<option value="12" <?=($product->billing_period == 12) ? "selected='selected'" : ""?>>
Jährlich
</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="billing_delay">Verzögerter
Verrechnungsstart</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="billing_delay"
id="billing_delay" placeholder="Freimonate"
value="<?=$contract->billing_delay?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="billing_delay">Fertigstellungsdatum</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="finish_date" id="finish_date" value="" />
</div>
</div>
<?php if((is_array($contract->linkFrom) && count($contract->linkFrom)) || (is_array($contract->linkTo) && count($contract->linkTo))): ?>
<h4 class="mt-4">Verknüpfte Verträge</h4>
<table class="table table-striped table-sm table-bordered table-hover"
id="link-table">
<tr>
<th title="Verlinkten Contract mit neuem Contract verknüpfen">
Übernehmen
</th>
<th title="Verlinkten Contract mit altem Contract zusammen kündigen">
Kündigen
</th>
<th>Kü.Datum</th>
<th>Kunde</th>
<th>Contract ID</th>
<th>Produkt</th>
<th>Matchcode</th>
<th>Bestelldatum</th>
<th>Fertigstellung</th>
<th>Kündigung</th>
</tr>
<?php foreach($contract->linksWithCredit as $link): ?>
<?php
if($link->contract_id == $contract->id) {
$linkcontract = $link->origin;
} else {
$linkcontract = $link->contract;
}
if($linkcontract->isCancelled()) continue;
?>
<tr data-link-type="<?=$link->type?>" class="<?=($hide_credit && $link->type == "credit") ? "hidden" : ""?>">
<td>
<input type="radio" class="form-check link-keep"
id="link-<?=$link->id?>-action-keep"
name="links[<?=$link->id?>][action]"
value="keep" <?=($linkcontract->cancel_date && $linkcontract->cancel_date < date('U')) ? "" : "checked='checked'"?>
onchange="linkActionChange(<?=$link->id?>)" />
<?php if($link->type == "credit"): ?>
(Gutschrift wird neu erstellt)
<?php endif; ?>
</td>
<td>
<input type="radio" class="form-check link-cancel"
id="link-<?=$link->id?>-action-cancel"
name="links[<?=$link->id?>][action]" value="cancel"
onchange="linkActionChange(<?=$link->id?>)" />
</td>
<td>
<input type="text" class="form-control hidden" id="link-<?=$link->id?>-cancel_date" name="links[<?=$link->id?>][cancel_date]" value="<?=$linkcontract->getRegularCanceldate()?>" />
</td>
<td>
<a href="<?=self::getUrl("Address", "View", ["id" => $linkcontract->owner_id])?>" target="_blank"><?=$linkcontract->owner->getCompanyOrName()?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>">
<a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>" target="_blank"><?=$linkcontract->id?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>">
<a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>" target="_blank"><?=$linkcontract->product_name?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>">
<a href="<?=self::getUrl("Contract", "View", ["contract_id" => $linkcontract->id])?>" target="_blank"><?=$linkcontract->matchcode?></a>
</td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->order_date) ? date('d.m.Y', $linkcontract->order_date) : ""?></td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->finish_date) ? date('d.m.Y', $linkcontract->finish_date) : ""?></td>
<td class="contract <?=($linkcontract->isCancelled()) ? "canceled" : ""?>"><?=($linkcontract->cancel_date) ? date('d.m.Y', $linkcontract->cancel_date) : ""?></td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
<!-- TODO: Fileupload -->
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="note">Interne Notiz</label>
<div class="col-lg-10">
<textarea id="note" class="form-control" name="note"
rows="5"><?=$contract->note?></textarea>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col text-center">
<input type="submit" class="btn btn-purple" value="Produktwechsel speichern"/>
</div>
</div>
</form>
</div>
</div>
<script>
$(".select2").select2({
allowClear: true,
placeholder: ""
});
$("#finish_date").datepicker({
language: 'de',
format: "dd.mm.yyyy",
showWeekDays: true,
todayBtn: 'linked',
autoclose: true
});
/*
* product autocomplete
*/
<?php if($contract->product_id && is_object(($contract->product))): ?>
$('#product_id').autoComplete('set', {
value: <?=$contract->product_id?>,
text: '<?=($contract->product_id) ? str_replace("'", "\\'", str_replace(["\n", "\r"], " ", $contract->product->name)) . " [" . $contract->product_id . "]" : ""?>'
});
<?php else: ?>
$('#product_id').autoComplete();
<?php endif; ?>
$('#product_id').keydown(function () {
if (event.keyCode == 13) {
event.preventDefault();
return false;
}
});
$('#product_id').on("autocomplete.select", function (evt, item) {
if (item && item.value === 0) {
$('#product_id').autoComplete('set', null);
}
if (item && item.value) {
updateProduct(item.value);
}
});
// product autocomplete
function updateProduct() {
var pid = $('input[name=product_id]').val();
$.get("<?=self::getUrl("Product", "Api")?>",
{
"do": "getProduct",
product_id: pid
},
function (success) {
//console.log(success);
p = success.result.product;
$('#product_name').val(p.name);
//$('#product_info').val(p.name);
$('#billing_delay').val(p.billing_delay);
$('#billing_period').val(p.billing_period);
$('#price').val(p.price);
$('#price_setup').val(p.price_setup);
$('#price_nne').val(p.price_nne);
$('#price_nbe').val(p.price_nbe);
if (typeof p.attributes === 'object' && "termination_required" in p.attributes && p.attributes.termination_required == 1) {
$('#termination_id-line').show();
$('#termination_id').select2({
allowClear: true,
placeholder: ""
});
} else {
$('#termination_id-line').hide();
//$('#termination_id-' + id + '-line').hide();
}
// set credit-link to cancel if new product does not need credit
const attrib = p.attributes;
let crediting_partner = false;
let crediting_rate = 0;
if (crediting_partner in p.attributes) {
crediting_partner = parseInt(p.attributes.crediting_partner);
}
if (crediting_rate in p.attributes) {
crediting_rate = parseFloat(p.attributes.crediting_rate);
}
let price_nne = parseFloat(p.price_nne);
//console.log(p.price_nne, crediting_partner, crediting_rate);
if (price_nne || (crediting_partner && crediting_rate)) {
$("#link-table tr[data-link-type='credit'] input.link-keep").prop("checked", "checked");
}
if (!price_nne && (!crediting_partner || !crediting_rate)) {
$("#link-table tr[data-link-type='credit'] input.link-cancel").prop("checked", "checked");
}
},
'json');
}
function linkActionChange(link_id) {
//console.log($("#link-" + link_id + "-action-cancel").prop("checked"));
if($("#link-" + link_id + "-action-cancel").prop("checked") && $("#finish_date").val()) {
$("#link-" + link_id + "-cancel_date").show();
} else {
$("#link-" + link_id + "-cancel_date").hide();
}
//link-<?=$link->id?>-action-cancel
}
</script>

View File

@@ -0,0 +1,95 @@
<?php
$f = "o";
$hide_credit = true;
?>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<!-- start page title -->
<div class="row">
<div class="col-12">
<div class="page-title-box">
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="<?=self::getUrl("Dashboard")?>"><?=MFAPPNAME_SLUG?></a>
</li>
<li class="breadcrumb-item"><a href="<?=self::getUrl("Order")?>">Bestellungen</a></li>
<li class="breadcrumb-item active">Produkt-/Standortwechsel</li>
</ol>
</div>
<h4 class="page-title">Aktives Produkt</h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<a href="<?=self::getUrl("Order")?>" class="btn btn-sm btn-secondary mr-1"><i class="fas fa-list"></i> Zurück zu Bestellungen</a>
</div>
</div>
<div class="card border-top-success">
<div class="card-body">
<h3 class="text-center mb-3"><?=$contract->product_name?> (<?=$contract->id?>)</h3>
<table class="table table-sm table-striped view-table">
<tr>
<th style="max-width: 50vw;">Matchcode:</th>
<td style="width: 50vw;"><?=$contract->matchcode?></td>
</tr><tr>
<th>Vertragsinhaber:</th>
<td>
<a href="<?=self::getUrl("Address", "View", ["id" => $contract->owner->id])?>"><?=$contract->owner->getCompanyOrName()?>
(<?=$contract->owner->customer_number?>)
</a>
</td>
</tr><tr>
<th>Produkt:</th>
<td><?=$contract->product_name?> [<?=$contract->product_id?>
]<?=($contract->product_name != $contract->product->name) ? " <i>(" . $contract->product->name . ")</i>" : ""?></td>
</tr><tr>
<th>Produkt Info:</th>
<td><?=$contract->product_info?></td>
</tr><tr>
<th>Preis Netto:</th>
<td class="<?=($contract->price < 0) ? "text-danger" : ""?>">€ <?=number_format(($contract->amount != 1) ? $contract->price * $contract->amount : $contract->price, 4, ",", ".")?></td>
</tr><tr>
<th>Preis Brutto:</th>
<td class="<?=($contract->price < 0) ? "text-danger" : ""?>">€
<?php if($contract->price && $contract->vatrate): ?>
<?php if($contract->amount != 1): ?>
<?=number_format($contract->price + ($contract->price / 100) * $contract->vatrate, 4, ",", ".")?>
<?php else: ?>
<?=number_format(($contract->price + ($contract->price / 100) * $contract->vatrate) * $contract->amount, 4, ",", ".")?>
<?php endif; ?>
<?php endif; ?>
</td>
</tr><tr>
<th>Fertigstellungsdatum:</th>
<td><?=date("d.m.Y", $contract->finish_date)?></td>
</tr>
</table>
</div>
</div>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage")."/Contract/include/productchange-action.php"); ?>
<div class="card">
<div class="card-body">
<a href="<?=self::getUrl("Order")?>" class="btn btn-sm btn-secondary mr-1"><i class="fas fa-list"></i> Zurück zu Bestellungen</a>
</div>
</div>
</div>
</div>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -346,6 +346,8 @@ class BillingController extends mfBaseController {
$total_days = $last_of_period->diff($first_of_period)->format("%a") + 1;
$period_days = ($end_date->diff($start_date)->format("%a")) + 1;
if($period_days < 0) continue; // don't bill for negative time range
$pc = $period_days / $total_days * 100;
$price = round($contract->price / 100 * $pc, 4);

View File

@@ -11,7 +11,7 @@ class ContractController extends mfBaseController
$this->me = $me;
$this->layout()->set("me", $me);
if (!$me->is(["Admin"])) {
if (!$me->is(["Admin", "salespartner", "netowner"])) {
$this->redirect("Dashboard");
}
}
@@ -19,6 +19,10 @@ class ContractController extends mfBaseController
protected function indexAction()
{
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$this->layout()->setTemplate("Contract/Index");
if ($this->request->resetFilter) {
@@ -87,6 +91,10 @@ class ContractController extends mfBaseController
protected function viewAction()
{
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$this->layout()->setTemplate("Contract/View");
$id = $this->request->contract_id;
@@ -116,6 +124,9 @@ class ContractController extends mfBaseController
}
protected function cancelAction() {
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$this->layout()->setTemplate("Contract/CancelForm");
$id = $this->request->contract_id;
@@ -154,6 +165,9 @@ class ContractController extends mfBaseController
}
protected function saveCancel() {
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$r = $this->request;
$id = $r->contract_id;
@@ -212,6 +226,9 @@ class ContractController extends mfBaseController
}
protected function sendCancelNotification() {
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$contract_id = $this->request->contract_id;
$contract = new Contract($contract_id);
@@ -238,23 +255,65 @@ class ContractController extends mfBaseController
{
$this->layout()->setTemplate("Contract/ProductchangeForm");
$f = $this->request->f;
if(!$f) {
$f = "c"; // from Contract
}
$this->layout()->set("f", $f);
$id = $this->request->contract_id;
if (!$id) {
$id = $this->request->id;
}
if (!is_numeric($id) || !$id) {
$this->layout()->setFlash("Vertrag nicht gefunden", "error");
if($f == "o") {
$this->redirect("Order", "addUpgrade");
} else {
$this->redirect("Contract");
}
}
$contract = new Contract($id);
if (!$contract->id) {
$this->layout()->setFlash("Vertrag nicht gefunden", "error");
if($f == "o") {
$this->redirect("Order", "addUpgrade");
} else {
$this->redirect("Contract");
}
}
if($this->me->isAdmin()) {
$this->layout()->set("terminations", TerminationModel::getAll());
} else {
// check permissions
// check if correct network
$my_network_ids = [];
foreach($this->me->my_networks as $network) {
$my_network_ids[] = $network->id;
}
if($contract->termination_id) {
if(!in_array($contract->termination->network_id, $my_network_ids)) {
if($f == "o") {
// from Order, redirect back to Order
$this->layout()->setFlash("Keine Berechtigung", "error");
$this->redirect("Order", "addUpgrade", ["owner_id" => $contract->owner_id]);
}
}
}
$terms = TerminationModel::search(["network_id" => $my_network_ids]);
$this->layout()->set("terminations", $terms);
}
$this->layout()->set("contract", $contract);
$this->layout()->set("terminations", TerminationModel::getAll());
if ($this->request->filter) {
$this->layout()->set("filter", $this->request->filter);
@@ -266,20 +325,37 @@ class ContractController extends mfBaseController
protected function saveProductchangeAction()
{
if(!$this->me->is(["Admin", "salespartner", "netowner"])) {
$this->redirect("Dashboard");
}
$r = $this->request;
//var_dump($r->links);exit;
$f = $r->f;
if(!$f) {
$f = "c"; // from Contract
}
$id = $r->contract_id;
if (!is_numeric($id) || !$id) {
$this->layout()->setFlash("Vertrag nicht gefunden", "error");
if($f == "o") {
$this->redirect("Order", "addUpgrade");
} else {
$this->redirect("Contract");
}
}
$contract = new Contract($id);
if (!$contract->id) {
$this->layout()->setFlash("Vertrag nicht gefunden", "error");
if($f == "o") {
$this->redirect("Order", "addUpgrade");
} else {
$this->redirect("Contract");
}
}
$new_contract = clone($contract);
@@ -303,9 +379,14 @@ class ContractController extends mfBaseController
$product = new Product($r->product_id);
if (!$product->id) {
$this->layout()->setFlash("Produkt nicht gefunden", "error");
if($f == "o") {
$this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]);
} else {
$this->redirect("Contract", "productchange", ["contract_id" => $id]);
}
}
$contract_data['product_external'] = $product->external;
$contract_data['product_external_id'] = $product->external_id;
$contract_data['sla_id'] = $product->sla_id;
@@ -315,8 +396,12 @@ class ContractController extends mfBaseController
$finish_date = DateTime::createFromFormat("d.m.Y", $r->finish_date, new DateTimeZone("Europe/Vienna"));
} catch (Exception $e) {
$this->layout()->setFlash("Ungültiges Kündigungsdateum", "error");
if($f == "o") {
$this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]);
} else {
$this->redirect("Contract", "productchange", ["contract_id" => $id]);
}
}
$finish_date->setTime(0,0,0);
$contract_data["finish_date"] = $finish_date->getTimestamp();
@@ -334,8 +419,12 @@ class ContractController extends mfBaseController
if (!$contract_data['termination_id'] || !$termination->id) {
$this->layout()->setFlash("Produkt erfordert Anschluss.", "error");
if($f == "o") {
$this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]);
} else {
$this->redirect("Contract", "productchange", ["contract_id" => $id]);
}
}
} else {
$contract_data['termination_id'] = null;
}
@@ -371,9 +460,13 @@ class ContractController extends mfBaseController
$cancel_date = DateTime::createFromFormat("d.m.Y", $link_data["cancel_date"], new DateTimeZone("Europe/Vienna"));
} catch (Exception $e) {
$this->layout()->setFlash("Ungültiges Kündigungsdateum", "error");
if($f == "o") {
$this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]);
} else {
$this->redirect("Contract", "productchange", ["contract_id" => $id]);
}
}
}
$old_link = new ContractLink($link_id);
@@ -408,7 +501,7 @@ class ContractController extends mfBaseController
}
if ($action == "cancel") {
if($cancel_date) {
if($cancel_date && $contract_cancel_date) {
// insert cancel_date in old contract
$lc = new Contract($origin_id);
$lc->cancel_date = $cancel_date->getTimestamp();
@@ -497,13 +590,21 @@ class ContractController extends mfBaseController
}
$this->layout()->setFlash("Neuer Contract erfolgreich erstellt", "success");
if($f == "o") {
$this->redirect("Order");
} else {
$this->redirect("Contract", "view", ["contract_id" => $new_contract_id]);
}
}
protected function finishContractAction()
{
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$r = $this->request;
$id = $r->contract_id;
@@ -550,6 +651,9 @@ class ContractController extends mfBaseController
protected function addAction()
{
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$this->layout()->setTemplate("Contract/Form");
$this->layout()->set("terminations", TerminationModel::getAll());
@@ -569,6 +673,9 @@ class ContractController extends mfBaseController
protected function editAction()
{
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$id = $this->request->contract_id;
if (!$id) {
$id = $this->request->id;
@@ -602,6 +709,9 @@ class ContractController extends mfBaseController
protected function saveAction()
{
if(!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$r = $this->request;
//var_dump($r);
@@ -787,7 +897,7 @@ class ContractController extends mfBaseController
protected function apiAction()
{
if (!$this->me->is(["Admin"])) {
if (!$this->me->is(["Admin", "salespartner", "netowner"])) {
$this->redirect("Dashboard");
}
$do = $this->request->do;
@@ -821,6 +931,10 @@ class ContractController extends mfBaseController
private function getContractApi()
{
if (!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$contract_id = $this->request->contract_id;
if (!is_numeric($contract_id) || $contract_id < 1) {
return false;
@@ -847,7 +961,37 @@ class ContractController extends mfBaseController
$return = [];
foreach(ContractModel::search(["owner_id" => $owner_id]) as $contract) {
$contracts = ContractModel::search(["owner_id" => $owner_id]);
if(!$contracts) {
header("Content-type: application/json");
echo json_encode([]);
exit;
}
$is_valid_owner = false;
if(!$this->me->is("Admin")) {
foreach($contracts as $contract) {
foreach(ContractLinkModel::includesContractId($contract->id) as $link) {
if($link->type != "credit") continue;
$link_contract = $link->contract;
if($link->contract_id == $contract->id) $link_contract = $link->origin;
if($link_contract->owner_id == $this->me->address_id) {
$is_valid_owner = true;
break;
}
}
}
if(!$is_valid_owner) {
header("Content-type: application/json");
echo json_encode([]);
exit;
}
}
foreach($contracts as $contract) {
$c = get_object_vars($contract->data);
$c["id"] = $contract->id;
$return[] = $c;
@@ -860,6 +1004,9 @@ class ContractController extends mfBaseController
private function findContractApi()
{
if (!$this->me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$search = trim($this->request->q);
$autocomplete = $this->request->autocomplete;

View File

@@ -371,18 +371,7 @@ class OrderController extends mfBaseController {
$users = [];
foreach($this->me->my_networks as $network) {
$network_ids[] = $network->id;
/*$tmp_users = $network->getAddressUsersByAddresstype("salespartner");
foreach($tmp_users as $user) {
if(!in_array($user->id, $users)) {
$users[] = $user->id;
}
}*/
}
/*
// get addresses from salespartner address' user ids
$addresses = AddressModel::search(["create_by" => $users]);
$this->layout()->set("addresses", $addresses);
*/
// get terminations in my networks
$terms = TerminationModel::search(["network_id" => $network_ids]);
$this->layout()->set("terminations", $terms);
@@ -438,6 +427,10 @@ class OrderController extends mfBaseController {
return $this->addAction();
}
protected function upgradesAction() {
}
protected function setwaitingAction() {
$order_id = $this->request->id;
$order = new Order($order_id);
@@ -471,12 +464,70 @@ class OrderController extends mfBaseController {
protected function addUpgrade() {
//$this->layout()->setTemplate("Order/Productchange");
Helper::renderVue($this, "OrderProductchange", $this->mod, ["CONTRACT_API_URL" => $this->getUrl("Contract", "api"),
Helper::renderVue($this, "OrderProductchange", "Neuer Produktwechsel", ["CONTRACT_API_URL" => $this->getUrl("Contract", "api"),
"ADDRESS_API_URL" => $this->getUrl("Address", "api"),
"CONTRACT_PRODUCTCHANGE_URL" => $this->getUrl("Contract", "productchange")]);
"ORDER_PRODUCTCHANGE_URL" => $this->getUrl("Order", "productchange")]);
}
protected function productchangeAction() {
$this->layout()->setTemplate("Order/ProductchangeForm");
$f = $this->request->f;
if(!$f) {
$f = "c"; // from Contract
}
$this->layout()->set("f", $f);
$id = $this->request->contract_id;
if (!$id) {
$id = $this->request->id;
}
if (!is_numeric($id) || !$id) {
$this->layout()->setFlash("Vertrag nicht gefunden", "error");
$this->redirect("Order", "addUpgrade");
}
$contract = new Contract($id);
if (!$contract->id) {
$this->layout()->setFlash("Vertrag nicht gefunden", "error");
$this->redirect("Order", "addUpgrade");
}
if($this->me->isAdmin()) {
$this->layout()->set("terminations", TerminationModel::getAll());
} else {
// check permissions
// check if correct network
$my_network_ids = [];
foreach($this->me->my_networks as $network) {
$my_network_ids[] = $network->id;
}
if($contract->termination_id) {
if(!in_array($contract->termination->network_id, $my_network_ids)) {
$this->layout()->setFlash("Keine Berechtigung", "error");
$this->redirect("Order", "addUpgrade", ["owner_id" => $contract->owner_id]);
}
}
$terms = TerminationModel::search(["network_id" => $my_network_ids]);
$this->layout()->set("terminations", $terms);
}
$this->layout()->set("contract", $contract);
if ($this->request->filter) {
$this->layout()->set("filter", $this->request->filter);
}
if ($this->request->s) {
$this->layout()->set("filter", $this->request->s);
}
}
protected function saveAction() {
$r = $this->request;
//var_dump($r->products);

View File

@@ -422,8 +422,31 @@ class ProductController extends mfBaseController {
$results = [];
if(!$this->me->isAdmin()) {
$my_product_ids = [];
$my_network_ids = [];
foreach($this->me->my_networks as $network) {
$my_network_ids[] = $network->id;
}
foreach(ProductNetworkModel::search(["network_id" => $my_network_ids]) as $pn) {
if(!$pn->product->active) continue;
if(!array_key_exists($pn->product_id, $my_product_ids)) {
$my_product_ids[] = $pn->product_id;
}
}
}
// return bootstrap-autocomplete format
foreach($products as $product) {
if(!$this->me->isAdmin()) {
if(!in_array($product->id, $my_product_ids)) continue;
}
$result = ['value' => $product->id, 'text' => str_replace("'", "\\'", str_replace(["\n", "\r"], " ",$product->name))];
$results[] = $result;
if(count($results) > 15) {

View File

@@ -1,55 +1,94 @@
Vue.component('OrderProductchange', {
//language=Vue
template: `
<tt-card style="min-height:50vh;">
<tt-card style="min-height:50vh;" class="border-top-purple">
<div class="row">
<div class="col">
<p class="alert alert-purple">Wählen Sie den Vertragsinhaber aus, um die aktiven Produkte anzuzeigen.<br />
Produktwechsel sollten immer mit dem Hauptprodukt durchgeführt werden. Dies ist fast immer das Internetzugangsprodukt.</p>
<tt-autocomplete :api-url="window['TT_CONFIG']['ADDRESS_API_URL'] + '?do=findAddress'"
v-model="owner_id" sm label="Vertragsinhaber auswählen"></tt-autocomplete>
v-model="owner_id" label="Vertragsinhaber suchen" placeholder="Tippen zum Suchen..."></tt-autocomplete>
<tt-table v-if="owner_id !== ''"
<div v-if="owner_id !== ''">
<tt-card class="col-6" v-if="owner_id !== '' && typeof owner === 'object'">
{{owner.name}}<br/>
{{owner.street}}<br/>
{{owner.zip}} {{owner.city}}
</tt-card>
<tt-table
:fetch-url="\`\${window['TT_CONFIG']['CONTRACT_API_URL']}?do=findContracts&owner_id=\${owner_id}\`"
:config="OrderProductchangeTableConfig"
small ref="contractTable">
:config="OrderProductchangeTableConfig" :small="false" class="sm"
disable-filtering ref="contractTable">
<template v-slot:actions="{ row }">
<a :href="window['TT_CONFIG']['BASE_URL'] + '/Contract/productchange?contract_id=' + row.id" class="btn btn-primary">Produktwechsel erstellen
</a>
<a :href="window['TT_CONFIG']['ORDER_PRODUCTCHANGE_URL'] + '?contract_id=' + row.id"
class="btn btn-purple"><i class="fas fa-fw fa-square-up"></i> Produktwechsel erstellen</a>
</template>
<template v-slot:billing_period="{ row }">
<span v-if="row.billing_period == 1">Monatlich</span>
<span v-else-if="row.billing_period == 12">Jährlich</span>
<span v-else-if="row.billing_period == 0">Einmalig</span>
<span v-else>{{row.billing_period}}</span>
</template>
<template v-slot:finish_date="{ row }">
<span v-if="row.finish_date > 0">{{window.moment.unix(row.finish_date).isValid() ? window.moment.unix(row.finish_date).format('DD.MM.YYYY') : ''}}</span>
</template>
<template v-slot:cancel_date="{ row }">
<span v-if="row.cancel_date > 0">{{window.moment.unix(row.cancel_date).isValid() ? window.moment.unix(row.cancel_date).format('DD.MM.YYYY') : ''}}</span>
</template>
<template v-slot:price="{ row }">
<span :class="(row.price < 0) ? 'text-danger' : ''">€ {{row.price | formatPrice}}</span>
</template>
<template v-slot:price_setup="{ row }">
<span :class="(row.price_setup < 0) ? 'text-danger' : ''">€ {{row.price_setup | formatPrice}}</span>
</template>
</tt-table>
</div>
</div>
</div>
</tt-card>
`, data() {
return {
window: window,
OrderProductchangeTableConfig: {
headers: [
{text: "Contract ID", key: "id", filter: false, order: false},
{text: "Produkt", key: "product_id", filter: false, order: false},
{text: "Matchcode", key: "matchcode", filter: false, order: false},
{text: "Preis p.P.", key: "price", filter: false, order: false},
{text: "Herstellungskosten", key: "price_setup", filter: false, order: false},
{text: "Fertigstellung", key: "finish_date", filter: false, order: false},
{text: "Kündigung", key: "cancel_date", filter: false, order: false},
{text: "Aktion", key: "actions", filter: false, order: false}
{text: "", key: "actions", class: "text-right", headerClass: "text-right"},
{text: "Contract ID", key: "id", class: "text-right", headerClass: "text-right"},
{text: "Produkt", key: "product_name", headerClass: "text-left"},
{text: "Matchcode", key: "matchcode", headerClass: "text-left"},
{text: "Preis", key: "price", headerClass: "text-left"},
{text: "Periode", key: "billing_period", headerClass: "text-left"},
{text: "Herstellungskosten", key: "price_setup", headerClass: "text-left"},
{text: "Fertigstellung", key: "finish_date", filter: "date", headerClass: "text-left"},
{text: "Kündigung", key: "cancel_date", filter: "date", headerClass: "text-left"}
],
tableHeader: 'Aktive Produkte',
tableHeader: 'Zu änderndes Produkt wählen',
key: 'OrderProductchange',
},
owner_id: "",
owner: false
}
},
methods: {
filters: {
formatPrice(price) {
roundedPrice = Math.round((parseFloat(price) + Number.EPSILON) * 100) / 100;
return roundedPrice.toFixed(4);
}
},
beforeMount() {
const urlSearchParams = new URLSearchParams(window.location.search);
if (urlSearchParams.has("owner_id")) {
this.owner_id = urlSearchParams.get("owner_id");
}
}
},
watch: {
owner_id: {
async handler() {
console.log(this.owner_id);
//this.$refs.contractTable.$set(this.$refs.contractTable.fetchUrl, `${this.window['TT_CONFIG']['CONTRACT_API_URL']}?do=findContracts&owner_id=${this.owner_id}`);
//this.$refs.contractTable.$set(this.$refs.contractTable.filters, 'owner_id', this.owner_id);
//await this.$refs.contractTable.fetchData();
}
}
}
})