/**
* Copyright (c) 2015 Mustafa DUMLUPINAR, mdumlupinar@gmail.com
*
* This file is part of seyhan project.
*
* seyhan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package controllers.admin;
import static play.data.Form.form;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import meta.GridHeader;
import meta.PageExtend;
import models.AdminDocument;
import models.AdminDocumentField;
import models.AdminDocumentTarget;
import models.temporal.DocumentMultiplier;
import models.temporal.PrintData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.Configuration;
import play.data.Form;
import play.data.validation.ValidationError;
import play.i18n.Messages;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Http.MultipartFormData;
import play.mvc.Http.MultipartFormData.FilePart;
import play.mvc.Result;
import utils.CacheUtils;
import utils.CloneUtils;
import utils.StringUtils;
import views.html.admins.document.form;
import views.html.admins.document.list;
import views.html.admins.document.multiplier;
import views.html.admins.document.print_form;
import com.google.common.reflect.TypeToken;
import com.seyhanproject.pserver.Document;
import com.seyhanproject.pserver.Printing;
import controllers.Application;
import documents.BankTransFields;
import documents.ChqbllPartialFields;
import documents.ChqbllPayrollFields;
import documents.ChqbllTransFields;
import documents.ContactTransFields;
import documents.Helper;
import documents.InvoiceTransFields;
import documents.OrderTransFields;
import documents.SafeTransFields;
import documents.StockTransFields;
import documents.WaybillTransFields;
import enums.ChqbllSort;
import enums.DocBand;
import enums.Module;
import enums.Right;
/**
* Belge tasarimlarini yapar. seyhan projesinde belgeler 2 ture ayrilir:
* 1- Tek banta sahip belgeler (cari, kasa ve banka hareketleri icin tasarlanabilen belgeler)
* 2- Cok banta sahip belgeler (stok, sipariş, fatura... hareketleri icin tasarlanabilen belgeler)
*
* Bantlar:
* 1- ReportTitle : Bir dokumde sadece ilk sayfada en basta dokumu yapilan banttir.
* 2- PageTitle : Her sayfada en basta (ilk sayfa icin ReportTitle dan hemen sonra) dokumu yapilan banttir.
* 3- ** Detail **: Diger tum bantlardan geriye kalan alanlara dokumu yapilan tekrarli hareket bilgilerini iceren banttir.
* 4- PageFooter : Her sayfada en sonda dokumu yapilan banttir.
* 5- ReportFooter: Bir dokumde sadece son sayfada en son (ve detay bandinin bittigi yerden baslayarak) dokumu yapilan banttir.
*
* Detail Bandini aciklamak icin ornek degerler
* Sayfadaki satir sayisi : 30
* Rapor Basi : 0
* Sayfa Basi : 3
* Sayfa Sonu : 2
* Rapor Sonu : 0
* bu durumda detay kismi 25 satir olacak (30 - (ReportTitle+PageTitle+PageFooter+ReportFooter))
*
* @author mdpinar
*/
public class Documents extends Controller {
private final static Logger log = LoggerFactory.getLogger(Documents.class);
private final static Form<AdminDocument> dataForm = form(AdminDocument.class);
/**
* Liste formu basliklarini doner
*
* @return List<GridHeader>
*/
private static List<GridHeader> getHeaderList() {
List<GridHeader> headerList = new ArrayList<GridHeader>();
headerList.add(new GridHeader(Messages.get("name"), "20%", true, null).sortable("name"));
headerList.add(new GridHeader(Messages.get("type"), "25%", true, null).sortable("right"));
headerList.add(new GridHeader(Messages.get("description")));
headerList.add(new GridHeader(Messages.get("is_active"), "7%", true));
return headerList;
}
/**
* Liste formunda gosterilecek verileri doner
*
* @return PageExtend
*/
private static PageExtend<AdminDocument> buildPage() {
List<Map<Integer, String>> dataList = new ArrayList<Map<Integer, String>>();
List<AdminDocument> modelList = AdminDocument.page();
if (modelList != null && modelList.size() > 0) {
for (AdminDocument model : modelList) {
Map<Integer, String> dataMap = new HashMap<Integer, String>();
int i = -1;
dataMap.put(i++, model.id.toString());
dataMap.put(i++, model.name);
dataMap.put(i++, Messages.get(model.right.key));
dataMap.put(i++, model.description);
dataMap.put(i++, model.isActive.toString());
dataList.add(dataMap);
}
}
return new PageExtend<AdminDocument>(getHeaderList(), dataList, null);
}
/**
* Liste formuna doner
*/
public static Result GO_HOME() {
return redirect(
controllers.admin.routes.Documents.list()
);
}
/**
* Uzerinde veri bulunan liste formunu doner
*/
public static Result list() {
if (! CacheUtils.isSuperUser()) return Application.getForbiddenResult();
return ok(list.render(buildPage()));
}
/**
* Kayit formundaki bilgileri kaydeder
*/
public static Result save() {
if (! CacheUtils.isSuperUser()) return Application.getForbiddenResult();
Form<AdminDocument> filledForm = dataForm.bindFromRequest();
Boolean isSinglePage = Boolean.parseBoolean(filledForm.data().get("isSinglePage"));
if(filledForm.hasErrors()) {
return badRequest(form.render(filledForm, isSinglePage));
} else {
AdminDocument model = filledForm.get();
List<AdminDocumentField> removeFieldList = new ArrayList<AdminDocumentField>();
if (model.reportTitleFields != null && model.reportTitleFields.size() > 0) {
for (AdminDocumentField field: model.reportTitleFields) {
if (field.band == null || field.type == null || field.name == null || field.name.trim().isEmpty()) {
removeFieldList.add(field);
continue;
}
}
model.reportTitleFields.removeAll(removeFieldList);
}
removeFieldList.clear();
if (model.pageTitleFields != null && model.pageTitleFields.size() > 0) {
for (AdminDocumentField field: model.pageTitleFields) {
if (field.band == null || field.type == null || field.name == null || field.name.trim().isEmpty()) {
removeFieldList.add(field);
continue;
}
}
model.pageTitleFields.removeAll(removeFieldList);
}
removeFieldList.clear();
for (AdminDocumentField field: model.detailFields) {
if (field.band == null || field.type == null || field.name == null || field.name.trim().isEmpty()) {
removeFieldList.add(field);
continue;
}
}
model.detailFields.removeAll(removeFieldList);
removeFieldList.clear();
if (model.pageFooterFields != null && model.pageFooterFields.size() > 0) {
for (AdminDocumentField field: model.pageFooterFields) {
if (field.band == null || field.type == null || field.name == null || field.name.trim().isEmpty()) {
removeFieldList.add(field);
continue;
}
}
model.pageFooterFields.removeAll(removeFieldList);
}
removeFieldList.clear();
if (model.reportFooterFields != null && model.reportFooterFields.size() > 0) {
for (AdminDocumentField field: model.reportFooterFields) {
if (field.band == null || field.type == null || field.name == null || field.name.trim().isEmpty()) {
removeFieldList.add(field);
continue;
}
}
model.reportFooterFields.removeAll(removeFieldList);
}
checkConstraints(filledForm);
if (filledForm.hasErrors()) {
return badRequest(form.render(filledForm, model.isSinglePage));
}
if (model.isActive == null) model.isActive = Boolean.TRUE;
if (model.isSinglePage == null) model.isSinglePage = Boolean.TRUE;
if (model.pageRows == null) model.pageRows = 66;
if (model.reportTitleRows == null) model.reportTitleRows = 0;
if (model.pageTitleRows == null) model.pageTitleRows = 0;
if (model.detailRows == null) model.detailRows = 0;
if (model.pageFooterRows == null) model.pageFooterRows = 0;
if (model.reportFooterRows == null) model.reportFooterRows = 0;
if (model.reportTitleLabels == null) model.reportTitleLabels = Boolean.FALSE;
if (model.pageTitleLabels == null) model.pageTitleLabels = Boolean.FALSE;
if (model.detailLabels == null) model.detailLabels = Boolean.FALSE;
if (model.pageFooterLabels == null) model.pageFooterLabels = Boolean.FALSE;
if (model.reportFooterLabels == null) model.reportFooterLabels = Boolean.FALSE;
if (model.leftMargin == null) model.leftMargin = 0;
if (model.topMargin == null) model.topMargin = 0;
if (model.bottomMargin == null) model.bottomMargin = 0;
if (model.carryingOverName != null && model.carryingOverName.trim().isEmpty()) model.carryingOverName = null;
try {
if (model.id == null) {
model.save();
} else {
model.update();
}
} catch (OptimisticLockException e) {
flash("error", Messages.get("exception.optimistic.lock"));
return badRequest(form.render(filledForm, model.isSinglePage));
}
flash("success", Messages.get("saved", model.name));
return GO_HOME();
}
}
/**
* Yeni bir kayit formu olusturur
*
* @param moduleName
*/
public static Result create(String moduleName) {
return screate(moduleName, null);
}
/**
* Modul ve belge basligina gore yeni bir kayit formu olusturur
*
* @param moduleName
* @param header
*/
public static Result screate(String moduleName, String header) {
if (! CacheUtils.isSuperUser()) return Application.getForbiddenResult();
AdminDocument document = new AdminDocument(Module.valueOf(moduleName), header);
return ok(form.render(dataForm.fill(document), document.isSinglePage));
}
/**
* Secilen kayit icin duzenleme formunu acar
*
* @param id
*/
public static Result edit(Integer id) {
if (! CacheUtils.isSuperUser()) return Application.getForbiddenResult();
if (id == null) {
flash("error", Messages.get("id.is.null"));
} else {
AdminDocument model = AdminDocument.findById(id);
if (model == null) {
flash("error", Messages.get("not.found", Messages.get("design")));
} else {
return ok(form.render(dataForm.fill(model), model.isSinglePage));
}
}
return GO_HOME();
}
/**
* Duzenlemek icin acilmis olan kaydi siler
*
* @param id
*/
public static Result remove(Integer id) {
if (! CacheUtils.isSuperUser()) return Application.getForbiddenResult();
if (id == null) {
flash("error", Messages.get("id.is.null"));
} else {
AdminDocument model = AdminDocument.findById(id);
if (model == null) {
flash("error", Messages.get("not.found", Messages.get("design")));
} else {
try {
model.delete();
flash("success", Messages.get("deleted", model.name));
} catch (PersistenceException pe) {
flash("error", Messages.get("delete.violation", model.name));
return badRequest(form.render(dataForm.fill(model), model.isSinglePage));
}
}
}
return GO_HOME();
}
/**
* Secilen kaydin kopyasini olusturur
*
* @param id
*/
public static Result createClone(Integer id) {
if (! CacheUtils.isSuperUser()) return Application.getForbiddenResult();
AdminDocument source = AdminDocument.findById(id);
DocumentMultiplier dm = new DocumentMultiplier();
dm.id = id;
dm.module = source.module;
dm.header = source.header;
dm.right = source.right;
dm.name = source.name;
dm.description = source.description;
Form<DocumentMultiplier> imDataForm = form(DocumentMultiplier.class);
return ok(
multiplier.render(imDataForm.fill(dm))
);
}
/**
* Yeni kopyayi kaydeder
*/
public static Result saveClone() {
if (! CacheUtils.isSuperUser()) return Application.getForbiddenResult();
Form<DocumentMultiplier> stmDataForm = form(DocumentMultiplier.class);
Form<DocumentMultiplier> filledForm = stmDataForm.bindFromRequest();
DocumentMultiplier dm = filledForm.get();
checkCloneConstraints(filledForm);
if (filledForm.hasErrors()) {
return badRequest(multiplier.render(filledForm));
}
AdminDocument source = AdminDocument.findForCloning(dm.id);
AdminDocument clone = CloneUtils.cloneModel(source);
clone.id = null;
clone.module = dm.module;
clone.header = dm.header;
clone.right = dm.right;
clone.name = dm.name;
clone.templateRows = source.templateRows;
clone.description = dm.description;
clone.isActive = Boolean.TRUE;
for (AdminDocumentField fld : clone.reportTitleFields) {
fld.id = null;
fld.reportTitleDoc = clone;
CloneUtils.resetModel(fld);
}
for (AdminDocumentField fld : clone.pageTitleFields) {
fld.id = null;
fld.pageTitleDoc = clone;
CloneUtils.resetModel(fld);
}
for (AdminDocumentField fld : clone.detailFields) {
fld.id = null;
fld.detailDoc = clone;
CloneUtils.resetModel(fld);
}
for (AdminDocumentField fld : clone.pageFooterFields) {
fld.id = null;
fld.pageFooterDoc = clone;
CloneUtils.resetModel(fld);
}
for (AdminDocumentField fld : clone.reportFooterFields) {
fld.id = null;
fld.reportFooterDoc = clone;
CloneUtils.resetModel(fld);
}
clone.save();
return ok(Messages.get("saved", clone.name));
}
/**
* Secilen hareket kaydi icin uzerinde yazdirma secenekleri bulunan formu acar
*
* @param modelId
* @param rightName
*/
public static Result showPrintForm(Integer modelId, String rightName) {
Right right = Right.findRight(rightName);
Map<String, String> options = AdminDocumentTarget.options();
if (options == null || options.size() < 1) {
return ok("<p><span class='label label-important'>"+Messages.get("alert")+"</span><br/>"+Messages.get("any.design.target.found.firstly.do")+"</p>");
}
if (right != null) {
options = AdminDocument.options(right);
}
if (options != null && options.size() > 0) {
PrintData pd = new PrintData();
pd.right = right;
pd.modelId = modelId;
Form<PrintData> dataForm = form(PrintData.class);
return ok(
print_form.render(dataForm.fill(pd), right)
);
} else {
return ok("<p><span class='label label-important'>"+Messages.get("alert")+"</span><br/>"+Messages.get("any.design.found.firstly.do")+"</p>");
}
}
/**
* Secilen hareket kaydini secilen hedefe gonderir
*/
public static Result printDocument() {
if (! CacheUtils.isLoggedIn()) return Application.login();
Form<PrintData> prnDataForm = form(PrintData.class);
Form<PrintData> filledForm = prnDataForm.bindFromRequest();
Right right = Right.findRight(dataForm.data().get("right"));
String result = "error";
if(filledForm.hasErrors()) {
return badRequest(print_form.render(filledForm, right));
} else {
PrintData model = filledForm.get();
if (model.document != null && model.document.id != null && model.target != null) {
String[] targetInfo = model.target.split("\\|");
AdminDocument document = AdminDocument.findById(model.document.id);
AdminDocumentTarget target = AdminDocumentTarget.findById(new Integer(targetInfo[0]));
if (model.document != null && model.document.id != null && model.modelId != null) {
Document doc = new Document();
doc.brokerIp = Configuration.root().getString("seyhan.mq.ip");
doc.userIp = Http.Context.current().request().remoteAddress();
doc.username = CacheUtils.getUser().username;
doc.workspace = CacheUtils.getWorkspaceName();
doc.right = model.right.name();
doc.id = model.modelId;
doc.isLocal = target.isLocal;
doc.path = target.path;
doc.targetName = target.name;
doc.targetType = target.targetType.ordinal();
doc.viewType = target.viewType.ordinal();
doc.isCompressed = target.isCompressed;
doc.pageRows = document.pageRows;
doc.rows = Helper.buildPage(document, doc.id);
Printing.send(doc);
result = "success";
}
}
}
return ok(result);
}
/**
* Daha onceden disa aktarilmis olan belge tasarim(lar)ini iceriye aktarir
*/
@SuppressWarnings("serial")
public static Result imbort() {
if (! CacheUtils.isLoggedIn()) return Application.login();
String ct = "file is null!";
MultipartFormData body = request().body().asMultipartFormData();
FilePart file = body.getFile("file");
if (file != null) {
ct = "content format isn't json!";
ct = file.getContentType();
if (file.getFilename().endsWith(".json") || file.getContentType().contains("json")) {
try {
BufferedReader br = new BufferedReader(new FileReader(file.getFile()));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
List<AdminDocument> docList = StringUtils.fromJson(sb.toString(), new TypeToken<List<AdminDocument>>(){});
for (AdminDocument doc : docList) {
String newName = AdminDocument.findLastName(doc.name);
if (newName != null) doc.name = newName;
doc.save();
log.info(doc.right + " : " + doc.name + " has imported.");
}
flash("success", Messages.get("imported", file.getFilename()));
ct = null;
} catch (Exception e) {
ct = e.getMessage();
log.error("ERROR", e);
}
}
}
if (ct != null) flash("error", Messages.get("error.in.import", ct));
return Application.getCurrentPageResult();
}
/**
* Tasarlanmis belge(ler)i disariya aktarir
*/
public static Result export() {
if (! CacheUtils.isLoggedIn()) return Application.login();
response().setHeader("Content-Type", "text/json");
response().setHeader("Content-Disposition", "attachment; filename=documents.json");
flash("success", Messages.get("exported", Messages.get("documents"), "documents.json"));
return ok(
new ByteArrayInputStream(StringUtils.toJson(AdminDocument.listForExport()).getBytes())
);
}
/**
* Kopya kaydin kaydedilmeden once uygunlugunu denetler
*
* @param filledForm
*/
private static void checkCloneConstraints(Form<DocumentMultiplier> filledForm) {
DocumentMultiplier model = filledForm.get();
if (model.id == null) {
filledForm.reject("name", Messages.get("id.is.null"));
}
if (AdminDocument.isUsedForElse("name", model.name, null)) {
filledForm.reject("name", Messages.get("not.unique", model.name));
}
}
/**
* Belge bandlarinda bulunabilecek alanlari doner
*
* @param bandName
* @param moduleName
* @param header
*
* @return Map<String, String>
*/
public static Map<String, String> getBandFields(String bandName, String moduleName, String header) {
Module module = Module.valueOf(moduleName);
DocBand band = DocBand.valueOf(StringUtils.capitalize(bandName));
boolean isDetail = DocBand.Detail.equals(band);
boolean isReportFooter = DocBand.ReportFooter.equals(band);
switch (module) {
case contact: {
if (isDetail) {
return ContactTransFields.getOptions();
}
break;
}
case bank: {
if (isDetail) {
return BankTransFields.getOptions();
}
break;
}
case safe: {
if (isDetail) {
return SafeTransFields.getOptions();
}
break;
}
case stock: {
if (isDetail) {
return StockTransFields.getDetailOptions();
} else {
return StockTransFields.getMasterOptions(isReportFooter);
}
}
case order: {
if (isDetail) {
return OrderTransFields.getDetailOptions();
} else {
return OrderTransFields.getMasterOptions(isReportFooter);
}
}
case waybill: {
if (isDetail) {
return WaybillTransFields.getDetailOptions();
} else {
return WaybillTransFields.getMasterOptions(isReportFooter);
}
}
case invoice: {
if (isDetail) {
return InvoiceTransFields.getDetailOptions();
} else {
return InvoiceTransFields.getMasterOptions(isReportFooter);
}
}
case cheque: {
if (isDetail) {
if ("cheque_payroll".equals(header)) {
return ChqbllPayrollFields.getDetailOptions(ChqbllSort.Cheque);
} else if ("cheque_transaction".equals(header)) {
return ChqbllTransFields.getDetailOptions(ChqbllSort.Cheque);
} else if ("cheque_partial".equals(header)) {
return ChqbllPartialFields.getDetailOptions();
}
} else {
if ("cheque_payroll".equals(header)) {
return ChqbllPayrollFields.getMasterOptions(isReportFooter);
} else if ("cheque_transaction".equals(header)) {
return ChqbllTransFields.getMasterOptions(isReportFooter);
} else if ("cheque_partial".equals(header)) {
return ChqbllPartialFields.getMasterOptions(ChqbllSort.Cheque, isReportFooter);
}
}
}
case bill: {
if (isDetail) {
if ("bill_payroll".equals(header)) {
return ChqbllPayrollFields.getDetailOptions(ChqbllSort.Bill);
} else if ("bill_transaction".equals(header)) {
return ChqbllTransFields.getDetailOptions(ChqbllSort.Bill);
} else if ("bill_partial".equals(header)) {
return ChqbllPartialFields.getDetailOptions();
}
} else {
if ("bill_payroll".equals(header)) {
return ChqbllPayrollFields.getMasterOptions(isReportFooter);
} else if ("bill_transaction".equals(header)) {
return ChqbllTransFields.getMasterOptions(isReportFooter);
} else if ("bill_partial".equals(header)) {
return ChqbllPartialFields.getMasterOptions(ChqbllSort.Bill, isReportFooter);
}
}
}
}
return null;
}
/**
* Kayit isleminden once form uzerinde bulunan verilerin uygunlugunu kontrol eder
*
* @param filledForm
*/
private static void checkConstraints(Form<AdminDocument> filledForm) {
AdminDocument model = filledForm.get();
if (AdminDocument.isUsedForElse("name", model.name, model.id)) {
filledForm.reject("name", Messages.get("not.unique", model.name));
}
List<ValidationError> detailErrors = lookForErrors(DocBand.Detail, model.detailRows, model.detailFields);
if (model.detailRows == null || model.detailRows.intValue() < 1 || model.detailRows.intValue() > model.pageRows) {
detailErrors.add(new ValidationError(DocBand.Detail.name(), Messages.get("error.numberRangeByName", Messages.get("row_count"), 1, model.pageRows)));
}
if (detailErrors.size() > 0) {
filledForm.errors().put(DocBand.Detail.name(), detailErrors);
}
}
/**
* Kayit islemi icin ekstra denetimler
*
* @param band
* @param limit
* @param fields
*
* @see #checkConstraints(Form)
* @return List<ValidationError>
*/
private static List<ValidationError> lookForErrors(DocBand band, int limit, List<AdminDocumentField> fields) {
List<ValidationError> result = new ArrayList<ValidationError>();
if (fields != null && fields.size() > 0) {
for (int i = 1; i < fields.size() + 1; i++) {
AdminDocumentField field = fields.get(i-1);
switch (field.type) {
case LINE:
case STATIC_TEXT: {
if (field.value == null || field.value.trim().isEmpty()) {
result.add(new ValidationError(field.band.name(), Messages.get("is.not.null.for.table", i, Messages.get("value"))));
}
break;
}
default: {
if (field.row == null || field.row <= 0 || field.column == null || field.column <= 0 || field.width == null || field.width <= 0) {
result.add(new ValidationError(field.band.name(), Messages.get("triple.cannot.be.zero.table", i)));
}
if (field.row != null && field.row > limit) {
result.add(new ValidationError(field.band.name(), Messages.get("too.high.for.table", i, Messages.get("row"), limit)));
}
if (field.column != null && field.column > 132) {
result.add(new ValidationError(field.band.name(), Messages.get("too.high.for.table", i, Messages.get("column"), 132)));
}
if (field.width != null && field.width > 132) {
result.add(new ValidationError(field.band.name(), Messages.get("too.high.for.table", i, Messages.get("width"), 132)));
}
}
}
}
} else if (DocBand.Detail.equals(band)) {
result.add(new ValidationError(band.name(), Messages.get("table.min.row.alert")));
}
return result;
}
}