Accounting-Companion / TallyConnector

You can use Tally Connector to Connect your desktop/Mobile Applications with Tally seamlessly.
47 stars 29 forks source link

Get Godown wise quantities of a Stock item from Batch table #38

Closed aquib-sh closed 7 months ago

aquib-sh commented 7 months ago

I want to get the godown wise quantity for an item, I have learned that Batch table in tally contains details about it. I can sync the batch table from Tally Connector by creating a custom class but the batch details do not show unless we put itemname in childof

As you might have guessed this is not a very feasible solution if I want to fetch all the batches and upload it where to be used later.

Is there a way to get all the batches? And all the primary also in general? Like when getting the data we don't get primary group, primary stock group etc that are default by tally.

Am I missing something here?

I understand it might not be directly related to this library and there might be some misunderstanding in my knowledge of Tally. Thanks for your help and understanding.

saivineeth100 commented 7 months ago

Your use case requires adding more than one collection, so you need to create your request Envelope

In tally we have walk attribute inside collection which is like select Many in LINQ we need to use that to select child's of parent object

this will be useful if you want get all child's irrespective of parent,

const string srcCollName = "TC_SrcStockItemsCOll";
const string collName = "TC_CustomBatchCollection";
RequestEnvelope requestEnvelope = new RequestEnvelope(HType.Collection, collName);
TDLMessage tDLMessage = requestEnvelope.Body.Desc.TDL.TDLMessage;

tDLMessage.Collection = [new Collection(srcCollName, colType: "StockItem"), new() { Name = collName, Collections = srcCollName, Walk = "BatchAllocations", NativeFields = ["*"] }];

var reqxml = requestEnvelope.GetXML();
TallyResult tallyResult = await _service.SendRequestAsync(reqxml, "Batch Allocations - All Items");
var envelope =  XMLToObject.GetObjfromXml<Envelope<CustomItemAllocationType>>(tallyResult.Response);
var items = envelope?.Body.Data.Collection?.Objects;
aquib-sh commented 7 months ago

Hello @saivineeth100 I am getting a problem while deserializing the batch class

This is the XML Request that I need to send to tally

<ENVELOPE Action="">
    <HEADER>
        <VERSION>1</VERSION>
        <TALLYREQUEST>EXPORT</TALLYREQUEST>
        <TYPE>COLLECTION</TYPE>
        <ID>TC_CustomBatchCollection</ID>
    </HEADER>
    <BODY>
        <DESC>
            <STATICVARIABLES>
                <SVEXPORTFORMAT>$$SysName:XML</SVEXPORTFORMAT>
            </STATICVARIABLES>
            <TDL>
                <TDLMESSAGE>
                    <COLLECTION ISMODIFY="No" ISFIXED="No" ISINITIALIZE="No" ISOPTION="No" ISINTERNAL="No" NAME="TC_SrcStockItemsCOll">
                        <TYPE>StockItem</TYPE>
                        <NATIVEMETHOD>NAME</NATIVEMETHOD>
                    </COLLECTION>
                    <COLLECTION ISMODIFY="No" ISFIXED="No" ISINITIALIZE="No" ISOPTION="No" ISINTERNAL="No" NAME="TC_AllBatches">
                        <TYPE>Batch</TYPE>
                        <CHILDOF>$NAME</CHILDOF>
                        <FETCH>*.*</FETCH>
                        <FETCH>CLOSINGBALANCE</FETCH>
                        <FETCH>GODOWNNAME</FETCH>
                    </COLLECTION>
                    <COLLECTION ISMODIFY="No" ISFIXED="No" ISINITIALIZE="No" ISOPTION="No" ISINTERNAL="No" NAME="TC_CustomBatchCollection">
                        <COLLECTION>TC_AllBatches:TC_SrcStockItemsCOll</COLLECTION>
                        <FETCH>*.*</FETCH>
                    </COLLECTION>
                </TDLMESSAGE>
            </TDL>
        </DESC>
    </BODY>
</ENVELOPE>

I created a custom Batch class to get the values exactly for the fields I am getting

using TallyConnector.Core.Models;

[XmlRoot(ElementName = "BATCH")]
public class Batch : TallyBaseObject
{
    [XmlElement(ElementName = "BATCHNAME")]
    public string Name { get; set; }

    [XmlElement(ElementName = "PARENT")]
    public string LedgerName { get; set; }

    [XmlElement(ElementName = "DATE")]
    public TallyDate Date { get; set; }

    [XmlElement(ElementName = "MFDON")]
    public TallyDate ManufacturingDate { get; set; }

    [XmlElement(ElementName = "GODOWNNAME")]
    public string GodownName { get; set; }

    [XmlElement(ElementName = "CLOSINGBALANCE")]
    public TallyAmount ClosingBal { get; set; }
}

This is the method I a using to do it, I tweaked your Collection model a bit to include XMLRootElement("COLLECTION") as NormalCollection and Fetchfields in additonal to the nativFields provided in it (Maybe it wasn't needed afterall) but I wanted to get the exact XML like I have shown above and avoid using Native fields and source collection because it wasn't able to find it in SOURCECOLLECTION in Tally

public void UploadBatch()
        {
            const string srcCollName = "TC_SrcStockItemsCOll";
            const string srcCollName2 = "TC_AllBatches";
            const string collName = "TC_CustomBatchCollection";

            RequestEnvelope requestEnvelope = new RequestEnvelope(HType.Collection, collName);
            TDLMessage tDLMessage = requestEnvelope.Body.Desc.TDL.TDLMessage;

            tDLMessage.Collection = [
                new Collection(srcCollName, colType: "StockItem",nativeFields: ["NAME"] ), 
                new Collection{Name=srcCollName2, Type= "Batch", Childof= "$NAME",
                    FetchFields= [".", "CLOSINGBALANCE", "GODOWNNAME"] 
                }, 
                new Collection{ Name = collName, NormalCollections = $"{srcCollName2}:{srcCollName}", FetchFields = ["."] }
           ];

            var reqxml = requestEnvelope.GetXML();
            TallyResult tallyResult = tally.SendRequestAsync(reqxml, "Batch Allocations - All Items").Result;
            var envelope =  XMLToObject.GetObjfromXml<Envelope<Batch>>(tallyResult.Response);
            var items = envelope?.Body.Data.Collection?.Objects; 
        }

So the result was I debugged and the ReqXML was getting formed correctly, the response XML was also proper from Tally but it wasn't able to serialize it in Batch structure and was getting null instead of a list of Batch.

What do you think I am missing here?

saivineeth100 commented 7 months ago

I missed one thing, we need to set xmlattributes as per object, this is done automatically if you use GetObjectsmethod, Since we are not using that we need to set them manually


XMLAttributeOverrides xMLAttributeOverrides = new();
XmlAttributes attrs = new();
attrs.XmlElements.Add(new("BATCH"));
xMLAttributeOverrides.Add(typeof(Colllection<Batch>), "Objects", attrs);
var envelope =  XMLToObject.GetObjfromXml<Envelope<Batch>>(tallyResult.Response,xMLAttributeOverrides );
aquib-sh commented 7 months ago

How do I specify company and other request or collection options in this approach?

saivineeth100 commented 7 months ago

How do I specify company and other request or collection options in this approach?

Refer implementation here