0 votes

See screenshot below. I would like to use a button which triggers a serie (>1) of products automatically linked to the document. The serie of products to be loaded depends on the linked project and is based on the type of project. This last part is less important, my main question is how to realize the first part: how to add multiple products to the document.

How to automatically add products here

asked in WorkFlow / Serverscript by (210 points)

2 Answers

0 votes

Hello Koen.

I worked it out for you. These are the files you have to create or append in your custom folder.

macros\MacroEditCustom.txt: Registering the custom require module and the new button to launch the serverscript.

MainJsModuleCustom {[custom/main/edit]}

EditCmdsTools.Docu {[<%IfReadOnly(else=|CmdTemplate;CmdInstantMail;|)%>CmdScan;CmdConvertToMail;CmdConvertToOppo;CmdInsertDetailProd]}

CmdInsertDetailProd {[<%Macro(name=$macro$, $_more$=$more$, $class$="", $icon$="i-Prod", $caption$="Insert Project products", $msg$="insertMainProjProd", $macro_sub_menu$="")%>]}

js\main\edit.js: load the custom command module

define([
  'custom/commands/editCmd',
], function(editCmd) {

});

js\commands\editCmd.js: Ajax request to serverscript, refresh state when finished. Show alert on server side exception.

define([
    'commands/editCmd',
    'model',
    'format'
], function(StandardEditCmd, Model, format) {

    var insertMainProjProd = function() {
        $.ajax({
            url: format("dialog?_macrofile=MacroAjax&_macro=RunScript&file=insertDetails;libjson&func=insertDetailsFromMainDetail&editHandle={editHandle}&mainDetail=Proj&detail=Prod"),
            type: "GET",
            success: function (html, textStatus, jqXHR) {
                if (IsNotEfficyErrorHtml(html, function(errorMsg) {alert(errorMsg)})) {
                    CebPerform("CEB_STATE");
                }
            }
        });
    }

    // Public commands to return
    StandardEditCmd.commands.set({
        'insertMainProjProd': insertMainProjProd
    });

    return StandardEditCmd;
});

serverscripts\insertDetails.js: The server script converts the request arguments using the entity catalog, it's written as a generic function. It gets the key of the main linked project, opens the consult on this project and executes the default linked products query. While looping this dataset, products are inserted on the edit context of the document.

function insertDetailsFromMainDetail() {
    var 
        editHandle = StrToIntDef(Request.Argument("editHandle"), 0),
        mainDetail = Database.EntityCatalog.GetEntityHandle(Request.Argument("mainDetail")), // Converts 'Proj' to 20
        detail = Database.EntityCatalog.GetEntityHandle(Request.Argument("detail")), // Converts 'Prod' to 30
        detailKeyName = Database.EntityCatalog.KeyFieldName(detail), // returns K_PRODUCT
        queryHandle = 0;

    var k_MainDetail = Database.getMainDetail(editHandle, mainDetail);
    if (!k_MainDetail) return 0;

    var detailContext = Database.openConsultContext(mainDetail);
    try {
        var dsSource = Database.ConsultDetail(queryHandle, detailContext, k_MainDetail, detail, false, true, 0);
        dsSource.first;
        while (!dsSource.eof) {
            var detailKey = dsSource.fieldByName(detailKeyName).asFloat;
            Database.insertDetail2(editHandle, detail, detailKey, false);
            dsSource.next;
        }
    } finally {
        Database.closeContext(detailContext);
    }
}

Screenshot of the result

I hope you understand the code and can use it.

answered by (6.8k points)
HI Kristof. I'm sorry for my very late reply. Many thanks for the quick help! I think we are in the right direction, but need a small chnage. Now I look at your answer I understand how you interpreted my question. But actually it needs to be a bit different. The products I want to add to the document are not linked to the project. What I meant is that based on the type of project I want to add a standard serie of products. This serie is pre-defined in some kind of template document.
Hopefully I'll be able to change the code you mentioned to the way I'm planning to use it. Again, Thanks for your help so far!
Actually I think I should rephrase my question.

I want to use one existing document as 'template' with a serie of attached products. The template document for example contains 5 products with serval prices and amounts. When pressing on the button as mentioned in the original screenshot, it should copy the products to the opened document. How should I do this?
0 votes

I think I solved it partly now using CopyDetails2 in my serverscript. The copy is coming from an existing template document with PRODUCTS, PRICES and QUANTITIES.The only problem I've got now is to also copy the column QUANTITY. Now it only copy's the standard settings for every product.

So my I've got 2 questions now:
1. How can I succesfully copy all details from the template, including the QUANTITY, PRICE and KSORT?
2. Is it a problem that K
RELATION in DOCUPROD is used more than once, as long as the KDOCUMENT and K_PRODUCT is different?

Database.CopyDetails2(editHandle, 31, templateKey, [ntProd], false, false);

My Complete code in editCmd.js

function docuAddProducts() {
    $.ajax({
        //deze regel gaat er nog vanuit dat de VM wordt gevulv vanuit een opportunity. Zo aanpassen dat dit flexibel wordt, ook voor projecten.
        url: format("dialog?_macrofile=MacroAjax&_macro=RunScript&file=Winkelwagentje;libjson&func=docuAddProducts&editHandle={editHandle}"),
        type: "GET",
        success: function (html, textStatus, jqXHR) {
            if (IsNotEfficyErrorHtml(html, function(errorMsg) {alert(errorMsg)})) {
                CebPerform("CEB_STATE");
            }
        }
    });
}

And my complete code in the serverscript

function docuAddProducts() { 
var editHandle = StrToFloatDef(Request.Argument("editHandle"), 0);
var Oppo = Database.GetMainDetail(editHandle, ntOppo);
var Proj = Database.GetMainDetail(editHandle, ntProj);
var dienst = 0

if (Oppo != 0){ 
    var oppoContext = Database.OpenConsultContext(ntOppo);
    var oppoDS = Database.Consult(oppoContext, Oppo, true);
    var dienst = oppoDS.FieldByName('F_DIENST').AsString;
    docuProdCopyDetails (dienst);
    Database.CloseContext(oppoContext);
    return;
}

if (Proj !=0){
    var projContext = Database.OpenConsultContext(ntProj);
    var projDS = Database.Consult(projContext, Proj, true);
    var dienst = projDS.FieldByName('F_DIENST').AsString;
    docuProdCopyDetails (dienst);
    Database.CloseContext(projContext);
    return;

}

function docuProdCopyDetails(dienst){
    var SQL = "select K_DOCU_TEMPLATE from LK_OPPO_DIENST where K_OPPO_DIENST = :Param1"; //per dienst wordt 1 VM aangewezen als template
    var tempContext = Database.OpenTemporaryContext();
    var tempDS = Database.ExecuteSystemSQLQuery(0, tempContext, SQL, dienst, true, true, 0);
    var templateKey = tempDS.FieldByName('K_DOCU_TEMPLATE').Value; //templateKey = de k_document van de template VM met het winkelwagentje per dienst
    if (templateKey > 0) {
        try {
            Database.CopyDetails2(editHandle, 31, templateKey, [ntProd], false, false); //31 = Documents
        }
        catch (error) {
        }               
    }
}

}

Thanks for your help!

answered by (210 points)
edited by
1,167 questions
1,425 answers
1,717 comments
325 users