Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Delphi Accpac comapi create batch invoice problem 1

Status
Not open for further replies.

EricComnut

Programmer
Mar 21, 2014
19
IE
Hi, we migrated our dll that connect to accpac from XAPI to COMAPI... Few things had change like the way we create view , open session.. change string and integer to olevariant but nothing major..
We can update and create customer, vendor in Accpac no problem

Now I just start testing the other options we have and see if the work and unfortunately I have a problem when I create an AR batch invoice list or an AP batch invoice list.
And the error is only an access violation. I spend a lot of time trying to figure out what it could be..
I recorded the macro in accpac to validate my code was not the same so I changed it.. even that didn't work out.
Checked with RVSPY and nothing is raised.
Here's what I have and my access violation happen on the PutWithoutVerification.
This code was working fine with XAPI
arrAccpacBatchAR0031[y].view.Browse ( '', False);
tmpValue := '1';
arrAccpacBatchAR0031[y].CNTBTCH.PutWithoutVerification(tmpValue);
arrAccpacBatchAR0031[y].View.Init;
Here is the macro
ARINVOICE3batch.Browse "((BTCHSTTS = 1) OR (BTCHSTTS = 7))", 1
ARINVOICE3batch.RecordCreate 1

ARINVOICE3batchFields("PROCESSCMD").PutWithoutVerification ("1") ' Process Command


They don't show the batch number and use the recordcreate.. so I did... And with this code I still have an access violation when I use the putwithoutverification.
Other places in the code we use the putwithoutverification and there is no problem...

Anybody would have an idea about what happen?
Thanks a million
 
Your views aren't composed correctly. I know this because you don't have to (and never should) put a value into arrAccpacBatchAR0031[y].CNTBTCH. It should only be

arrAccpacBatchAR0031.Cancel
arrAccpacBatchAR0031.RecordGenerate, 1
 
in my post I had the error of the browse that is not there that's one of the test
the old code is this with XAPI
arrAccpacBatchAR0031[y].CNTBTCH.PutWithoutVerification(0);
arrAccpacBatchAR0031[y].View.Init;
arrAccpacBatchAR0031[y].INVCTYPE.Value :=2; // Type Summary
the new one with comapi I had to create the olevariant and assign the value to it to be able to pass it.
tmpValue := 0;
arrAccpacBatchAR0031[y].CNTBTCH.PutWithoutVerification(tmpValue);
arrAccpacBatchAR0031[y].View.Init;
arrAccpacBatchAR0031[y].INVCTYPE.Value :=2; // Type Summary

Thanks for the reply tuba2007. if that is not supposed to be like that... I have no problem removing it but i'd like to understand why it is working fine for more than 10 years over all our customers. Is it something that was use with XAPI and now with COMAPI it is not?

thanks :)
 
Because the COMAPI is different! Here's all I do in VB:

With a4wLink
.OpenView "AR0031", ArInvoiceBatch
.OpenView "AR0032", ArInvoiceHeader
.OpenView "AR0033", ArInvoiceDetail1
.OpenView "AR0034", ArInvoiceDetail2
.OpenView "AR0402", ArHeaderOptional
.OpenView "AR0401", ArDetailOptional
End With

ArInvoiceBatch.Compose Array(ArInvoiceHeader)
ArInvoiceHeader.Compose Array(ArInvoiceBatch, ArInvoiceDetail1, ArInvoiceDetail2, ArHeaderOptional)
ArInvoiceDetail1.Compose Array(ArInvoiceHeader, ArInvoiceBatch, ArDetailOptional)
ArInvoiceDetail2.Compose Array(ArInvoiceHeader)
ArHeaderOptional.Compose Array(ArInvoiceHeader)
ArDetailOptional.Compose Array(ArInvoiceDetail1)


ArInvoiceBatch.Cancel
ArInvoiceBatch.Init
ArInvoiceBatch.Fields("BTCHDESC").Value = "xxxxx"
ArInvoiceBatch.Update
 
A little more in the XAPI version of our dll
// Open the view
arrAccpacBatchAR0031.View := arrAccpacSession.OpenView('AR0031', 'AR');
arrAccpacBatchAR0031.Fields := arrAccpacBatchAR0031.View.Fields;
arrAccpacBatchAR0031.CNTBTCH := GetxApiField(arrAccpacBatchAR0031.Fields,'CNTBTCH');
arrAccpacBatchAR0031.DATEBTCH := GetxApiField(arrAccpacBatchAR0031.Fields,'DATEBTCH');
arrAccpacBatchAR0031.BTCHDESC := GetxApiField(arrAccpacBatchAR0031.Fields,'BTCHDESC');
arrAccpacBatchAR0031.CNTINVCENT := GetxApiField(arrAccpacBatchAR0031.Fields,'CNTINVCENT');
arrAccpacBatchAR0031.AMTENTR := GetxApiField(arrAccpacBatchAR0031.Fields,'AMTENTR');
arrAccpacBatchAR0031.BTCHTYPE := GetxApiField(arrAccpacBatchAR0031.Fields,'BTCHTYPE');
arrAccpacBatchAR0031.BTCHSTTS := GetxApiField(arrAccpacBatchAR0031.Fields,'BTCHSTTS');
arrAccpacBatchAR0031.INVCTYPE := GetxApiField(arrAccpacBatchAR0031.Fields,'INVCTYPE');

//Compose view
arrAccpacBatchAR0031.View.Compose(arrAccpacInvoiceAR0032.View);

arrAccpacInvoiceAR0032.View.Compose( VarArrayOf([arrAccpacBatchAR0031.View,
arrAccpacDetInvAR0033.View,
arrAccpacTotInvAR0034.View]));

arrAccpacDetInvAR0033.View.Compose( VarArrayOf([arrAccpacInvoiceAR0032.View,
arrAccpacBatchAR0031.View]));
And then we use it...
After migration to comapi the compose view had to be changed to that to compile without error
TmpViews :=arrAccpacInvoiceAR0032.View;
arrAccpacBatchAR0031.View.Compose(TmpViews);

TmpViews := VarArrayOf([arrAccpacBatchAR0031.View,
arrAccpacDetInvAR0033.View,
arrAccpacTotInvAR0034.View]);
arrAccpacInvoiceAR0032.View.Compose( TmpViews);

TmpViews := VarArrayOf([arrAccpacInvoiceAR0032.View,
arrAccpacBatchAR0031.View]);
arrAccpacDetInvAR0033.View.Compose( TmpViews);
TmpViews := arrAccpacInvoiceAR0032.View;
arrAccpacTotInvAR0034.View.Compose(TmpViews);

Hope all the code we use will help to find out the problem :)
 
So in VB u just put the description of the batch and nothing else???
I will try right now :)
 
That was a snippet. I change the batch date sometimes. Here's the C# version:

a4wLink.OpenView("AR0031", out ArInvoiceBatch);
a4wLink.OpenView("AR0032", out ArInvoiceHeader);
a4wLink.OpenView("AR0033", out ArInvoiceDetail1);
a4wLink.OpenView("AR0034", out ArInvoiceDetail2);
a4wLink.OpenView("AR0402", out ArHeaderOptional);
a4wLink.OpenView("AR0401", out ArDetailOptional);

ArInvoiceBatch.Compose(new object[] {ArInvoiceHeader});
ArInvoiceHeader.Compose(new object[] {ArInvoiceBatch, ArInvoiceDetail1, ArInvoiceDetail2, ArHeaderOptional});
ArInvoiceDetail1.Compose(new object[] {ArInvoiceHeader, ArInvoiceBatch, ArDetailOptional});
ArInvoiceDetail2.Compose(new object[] {ArInvoiceHeader});
ArHeaderOptional.Compose(new object[] {ArInvoiceHeader});
ArDetailOptional.Compose(new object[] {ArInvoiceDetail1});

ArInvoiceBatch.RecordGenerate(true);
ArInvoiceBatch.Fields.FieldByName["BTCHDESC"].PutWithoutVerification("Springer Miller Import " + f.Name);

ArInvoiceHeader.RecordGenerate(false);
ArInvoiceHeader.Fields.FieldByName["INVCTYPE"].PutWithoutVerification("2");
ArInvoiceHeader.Fields.FieldByName["IDCUST"].PutWithoutVerification(sCust);
ArInvoiceHeader.Fields.FieldByName["IDINVC"].PutWithoutVerification(sInvoice);
ArInvoiceHeader.Fields.FieldByName["INVCDESC"].PutWithoutVerification(sComp);
ArInvoiceHeader.Fields.FieldByName["CUSTPO"].PutWithoutVerification(NoNull(reader,"conf_num"));
ArInvoiceHeader.Fields.FieldByName["ORDRNBR"].PutWithoutVerification(NoNull(reader, "unit"));
ArInvoiceHeader.Fields.FieldByName["DATEINVC"].PutWithoutVerification(reader[reader.GetOrdinal("tdate")].ToString());
ArInvoiceDetail1.RecordGenerate(false);
ArInvoiceDetail1.Fields.FieldByName["IDACCTREV"].PutWithoutVerification("4000");
ArInvoiceDetail1.Fields.FieldByName["AMTEXTN"].PutWithoutVerification(Math.Abs(Convert.ToDouble(NoNull(reader, "tcredit"))));
ArInvoiceDetail1.Insert();
ArInvoiceHeader.Insert();

 
Did exactely like your code and still raise and access violation when I try to set the value of BTCHDESC
 
Did you get rid of the .Browse and the arrAccpacBatchAR0031[y].CNTBTCH.PutWithoutVerification(tmpValue)?
 
yes I did that's the code I ran that had the access violation
tmpValue := 'AbakAP';
arrAccpacBatchAR0031[y].View.Cancel;
arrAccpacBatchAR0031[y].View.Init;
arrAccpacBatchAR0031[y].BTCHDESC.Set_Value(tmpValue);

Also I checked how I create the view and how u did it.. and we don't use the optionals other than that all seems to be same.. Normally I would have and exception raised.. not an access violation..
 
tmpValue := 'AbakAP';
arrAccpacBatchAR0031[y].View.Cancel;
arrAccpacBatchAR0031[y].View.RecordGenerate(True) ; // True or False same problem
arrAccpacBatchAR0031[y].BTCHDESC.Set_Value(tmpValue);

Still access violation when I try to assign the batch description.
 
Ok cool Tuba2007 and thanks a million for your time...
for what I can see from this thread the view is created same as you and for you it works..for me with comapi on AR and AP transfer I have access violation.. Same code with XAPI was working fine and still works fine for vendor and customers update and insert...
 
Are you sure you've removed all references to the Xapi? When I convert old Xapi code, I have to start with an empty file and add the COMAPI references from scratch.
 
Good question as I would have asked the same and yes no reference to xapi or even in the search path...
:)
 
Django here. :)

Here's the code that I use to do my compositions for AR Invoices. Now one thing that I did was to create a wrapper around the Accpac COMApi view. That's why I can call ARIHeader.OpenView(fDBLink,'AR0032',Success,Msg);

Wrapping the view also allows you to interact with the views in a much friendlier manner.

Code:
procedure TARInvoiceBatch2012.OpenAndComposeViews;
var
    va: OLEVariant; //view array
begin

     //open views
     ARIHeader.OpenView(fDBLink,'AR0032',Success,Msg);
     ARIHeaderOF.OpenView(fDBLink,'AR0402',Success,Msg);
     ARIDetail.OpenView(fDBLink,'AR0033',Success,Msg);
     ARIDetailOF.OpenView(fDBLink,'AR0401',Success,Msg);
     ARIBatch.OpenView(fDBLink,'AR0031',Success,Msg);
     ARIPaymentSch.OpenView(fDBLink,'AR0034',Success,Msg);

     //view composition
      va := VarArrayCreate([0,0],varVariant);
      va[0] := ARIHeader.View;
      ARIBatch.View.Compose(va);

      va := VarArrayCreate([0,3],varVariant);
      va[0] := ARIBatch.View;
      va[1] := ARIDetail.View;
      va[2] := ARIPaymentSch.View;
      va[3] := ARIHeaderOF.View;
      ARIHeader.View.Compose(va);

      va := VarArrayCreate([0,2],varVariant);
      va[0] := ARIHeader.View;
      va[1] := ARIBatch.View;
      va[2] := ARIDetailOF.View;
      ARIDetail.View.Compose(va);

      va := VarArrayCreate([0,0],varVariant);
      va[0] := ARIHeader.View;
      ARIPaymentSch.View.Compose(va);

      va := VarArrayCreate([0,0],varVariant);
      va[0] := ARIHeader.View;
      ARIHeaderOF.View.Compose(va);

      va := VarArrayCreate([0,0],varVariant);
      va[0] := ARIDetail.View;
      ARIDetailOF.View.Compose(va);

end;

Here's the interface section for my view wrapper which exposes the View methods along with error trapping.
Code:
    IXAccpacView = interface
        ['{9995F779-9CBB-46E1-A6D9-DC47792E19D4}']
        procedure SV(aFieldName: string; aValue: OLEVariant; var bSuccess: boolean; var bMsg: string);
        procedure PW(aFieldName: string; aValue: OLEVariant; var bSuccess: boolean; var bMsg: string);
        function GVint(aFieldName: string): integer; overload;
        function GVstr(aFieldName: string): string; overload;
        function GVstrBlank(aFieldName: string): Boolean;
        function GVdbl(aFieldName: string): Double; overload;
        function GVdate(aFieldName: string): TDateTime; overload;
        function GVbool(aFieldName: string): boolean; overload;
        procedure Process(var bSuccess: boolean; var bMsg: string);
        procedure Insert(var bSuccess: boolean; var bMsg: string);
        procedure Update(var bSuccess: boolean; var bMsg: string);
        procedure Post(var bSuccess: boolean; var bMsg: string);
        procedure Browse(aFilter: string; aForward: boolean; var bSuccess: boolean; var bMsg: string); overload;
        procedure Browse(aFilter: string; aForward: boolean); overload;
        function Fetch: boolean;
        procedure Init;
        procedure RecordCreate(aCreateOption: tagViewRecordCreateEnum; var bSuccess: Boolean; var bMsg: string); overload;
        procedure RecordCreate(aCreateOption: tagViewRecordCreateEnum); overload;
        procedure RecordClear;
        procedure RecordGenerate(aCreateNow: boolean);
        procedure Close;
        function Exists: boolean;
        function Dirty: boolean;
        procedure Cancel;
        procedure OpenView(aDBLink: AccpacDBLink; aRotoID: string; var bSuccess: boolean; var bMsg: string); overload;
        procedure OpenView(aDBLink: AccpacDBLink; aRotoID: string); overload;
        function Read: boolean;
        function View: IAccpacView;
        function GoTop: boolean;
        function GoBottom: boolean;
        function Next: Boolean;
        procedure Delete(var bSuccess: boolean; var bMsg: string);
        procedure Compose(const ViewArray: array of IXAccpacView);
        procedure MakeEmptyForCompose;
        function IsEmptyForCompose: Boolean;
        function Success: boolean;
        function Msg: string;
        procedure Reset;
        procedure SetOrder(aIndexNo: integer);

When I set a field value I call View.SV(fieldname, value, success, msg) which looks like the following. That way I never get hit with an error directly from the View and I can access the errors at a later point in the code.

Code:
procedure TXAccpacView.SV(aFieldName: string; aValue: OLEVariant; var bSuccess: boolean; var bMsg: string);
var
    err: string;
begin
    if not bSuccess then
        exit;

    try
        Self.FView.Fields.FieldByName[aFieldName].Set_Value(aValue);
    except
        on e: exception do begin
            bSuccess := false;
            err := GetAccpacErrors(Self.FView.Session, bSuccess);
            bMsg := bMsg + NativeLineFeed + err;
        end;
    end;
end;

And, finally, this is my routine for creating an AR invoice batch. (It looks like I'm calling SetValue on the PROCESSCMD field instead of PutWithoutVerification
Code:
function TARInvoiceBatch2012.Batch_Create(aBatchDesc: string; aBatchDate: TDateTime): string;
begin
    try
        ARIBatch.RecordCreate(VIEW_RECORD_CREATE_INSERT, Success, Msg);
        Batch_SV('PROCESSCMD',1);
        ARIBatch.Process(Success,Msg);
        ARIBatch.Read;

        Batch_SV('BTCHDESC',aBatchDesc);
        Batch_SV('DATEBTCH',aBatchDate);
        ARIBatch.Update(Success,Msg);

        result := ARIBatch.GVstr('CNTBTCH');
        FARIBatchNumber := result;
    except
        on e:exception do begin
            Success := False;
            Msg := GetAccpacErrors(fDBLink.Session);
            DB_Write(FDebugLevel,Msg);
        end;
    end;

    if not(Success) then DB_Write(FDebugLevel,'Failure in ARIBatch_CreateNew:'+Msg);
end;

I hope that helps!




 
Hi Django,
This really helps... as the way you assign the variable also work for us :))))))

I don't know just yet but I use your example..and when I do like you View.Fields.Fieldbyname('').SetValue...
Then no access violation...
so I'll check in the code as they are initialize like this...
type
TAccpacBatchAR0031 = record
View : IAccpacView;
Fields : IAccpacViewFields;
CNTBTCH : IAccpacViewField; // Numero de batch
DATEBTCH : IAccpacViewField; // Date de batch
PROCESSCMD : IAccpacViewField;
BTCHDESC : IAccpacViewField; // description de la batch
CNTINVCENT : IAccpacViewField; // Nombre d'entrées
AMTENTR : IAccpacViewField; // Total de la batch
BTCHTYPE : IAccpacViewField; // Imporoted 2
BTCHSTTS : IAccpacViewField; // Ready to post 7
INVCTYPE : IAccpacViewField; // Summary 2
end;

arrAccpacBatchAR0031 : Array of TAccpacBatchAR0031;

As we can have x sets of records we do that at the creation to initialize the array
SetLength(arrAccpacBatchAR0031, RecordCount);

Then we assign the fields
arrAccpacCieDbLink.OpenView( 'AR0031', arrAccpacBatchAR0031.View);
arrAccpacBatchAR0031.Fields := arrAccpacBatchAR0031.View.Fields;
arrAccpacBatchAR0031.CNTBTCH := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'CNTBTCH');
arrAccpacBatchAR0031.DATEBTCH := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'DATEBTCH');
arrAccpacBatchAR0031.BTCHDESC := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'BTCHDESC');
arrAccpacBatchAR0031.PROCESSCMD := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'PROCESSCMD');
arrAccpacBatchAR0031.CNTINVCENT := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'CNTINVCENT');
arrAccpacBatchAR0031.AMTENTR := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'AMTENTR');
arrAccpacBatchAR0031.BTCHTYPE := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'BTCHTYPE');
arrAccpacBatchAR0031.BTCHSTTS := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'BTCHSTTS');
arrAccpacBatchAR0031.INVCTYPE := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'INVCTYPE');


then compose the view
var TmpViews : oleVariant;

TmpViews :=arrAccpacInvoiceAR0032.View;
arrAccpacBatchAR0031.View.Compose(TmpViews);

TmpViews := VarArrayOf([arrAccpacBatchAR0031.View,
arrAccpacDetInvAR0033.View,
arrAccpacTotInvAR0034.View]);
arrAccpacInvoiceAR0032.View.Compose( TmpViews);

TmpViews := VarArrayOf([arrAccpacInvoiceAR0032.View,
arrAccpacBatchAR0031.View]);
arrAccpacDetInvAR0033.View.Compose( TmpViews);
TmpViews := arrAccpacInvoiceAR0032.View;
arrAccpacTotInvAR0034.View.Compose(TmpViews);

Then the process

// With this I got the error and nothing is nil all is assigned
tmpValue := 1;
arrAccpacBatchAR0031[y].PROCESSCMD.Set_Value(tmpValue);

// With your example this goes without a problem like before.
tmpValue := 1;
arrAccpacBatchAR0031[y].View.Fields.FieldByName['PROCESSCMD'].Set_Value(tmpValue);

Do you have any idea... I'll post what was the problem as soon as I know... but many many thanks your help is greatly appreciated:)
 
What does you GetIAccpacViewField code look like? Is it possible that arrAccpacBatchAR0031[y].PROCESSCMD is nil? You should also be able to run a4wrvSpy and see if the view is being called properly.
 
here is the function that is in the code since forever.
I admit it's a long way to get the field I need but I didn't write it and it works for customer and for vendors

function TdmACCPAC.GetIAccpacViewField( prmFields : IAccpacViewFields; prmFieldName : String ) : IAccpacViewField;
var
i : Word;
begin
Result := nil;
for i := 0 to (prmFields.Count - 1) do
begin
if Trim(prmFields.FieldByIndex.Name) = prmFieldName then
Result := prmFields.FieldByIndex;
end;
end;

The assignation that is made before creating the view.....
I checked before and after the compose view the function return the same pointer to the fields.
So nothing is nil.
if I do like you and go from. view.fields.fieldbyname[''].SetValue... all worked.

if I use this assignation below nothing work ...even the .fields doesn't work..
but strange as all other code to update a customer or a vendor do not generate error and all views are created the same way....
Something about the batch seems to be different.. but hey because of you... now I can change the code a little bit and make it works for the customers.

arrAccpacCieDbLink.OpenView( 'AR0031', arrAccpacBatchAR0031.View);
arrAccpacBatchAR0031.Fields := arrAccpacBatchAR0031.View.Fields;
arrAccpacBatchAR0031.CNTBTCH := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'CNTBTCH');
arrAccpacBatchAR0031.DATEBTCH := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'DATEBTCH');
arrAccpacBatchAR0031.BTCHDESC := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'BTCHDESC');
arrAccpacBatchAR0031.PROCESSCMD := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'PROCESSCMD');
arrAccpacBatchAR0031.CNTINVCENT := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'CNTINVCENT');
arrAccpacBatchAR0031.AMTENTR := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'AMTENTR');
arrAccpacBatchAR0031.BTCHTYPE := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'BTCHTYPE');
arrAccpacBatchAR0031.BTCHSTTS := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'BTCHSTTS');
arrAccpacBatchAR0031.INVCTYPE := GetIAccpacViewField(arrAccpacBatchAR0031.Fields,'INVCTYPE');

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top