# How to Create SSRS Reports in Dynamics 365

Bu yazımızda adım adım Dynamics 365'te SSRS rapor nasıl yapılıyor öğreneceğiz.

Öncelikle temp bir tablo oluşturalım. Table Type özelliğinin TempDB olmasına dikkat edelim. Tablomuzun alanlarını ekledikten sonra class’lara geçebiliriz.

![Temp Table](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831646789/018e1e02-5ffa-497c-8306-931f4b22266e.png align="center")

---

Sıra Contract, DP ve Controller class’larımızı oluşturmaya geldi. Bu class’lar için örnek kodları aşağıda paylaşıyorum. Siz kendi ihtiyaçlarınız doğrultusunda class’ları revize edebilirsiniz.

```csharp
[
    DataContractAttribute
]
public class ETGVendorPaymentOrderReportContract implements SysOperationValidatable
{
    LedgerJournalId ledgerJournalId;

    [
        DataMemberAttribute('ledgerJournalId'),
        SysOperationLabelAttribute(literalstr("@SYS328705")),
        SysOperationHelpTextAttribute(literalstr("@SYS328705")),
        SysOperationDisplayOrderAttribute('1')
    ]
    public LedgerJournalId parmLedgerJournalId(LedgerJournalId _ledgerJournalId = ledgerJournalId)
    {
        ledgerJournalId = _ledgerJournalId;
        return ledgerJournalId;
    }

    public boolean validate()
    {
        boolean isValid = true;

        if (!ledgerJournalId)
        {
            isValid = checkFailed(strfmt("Günlük zorunludur."));
        }

        return isValid;
    }

}
```

```csharp
[
    SRSReportParameterAttribute(classStr(ETGVendorPaymentOrderReportContract))
]
public class ETGVendorPaymentOrderReportDP extends SrsReportDataProviderPreProcessTempDB
{
    ETGVendorPaymentOrderReportTmp tmp;

    [SRSReportDataSetAttribute(tableStr(ETGVendorPaymentOrderReportTmp))]
    public ETGVendorPaymentOrderReportTmp getTmp()
    {
        select tmp;
        return tmp;
    }

    public void processReport()
    {
        ETGVendorPaymentOrderReportContract contract;
        LedgerJournalId ledgerJournalId;

        LedgerJournalTrans ledgerJournalTrans, ledgerJournalTransTotal;
        VendTable vendTable;
        VendBankAccount vendBankAccount;
        BankAccountTable bankAccountTable;
        PaxBankBranchTable paxBankBranchTable;
        BankAccountID bankAccountID;
        CompanyName companyName;
        int i;

        // Set the user connection to use on tables.
        // This is needed because the createdTransactionId is different for the report than the default connection.
        tmp.setConnection(this.parmUserConnection());

        contract = this.parmDataContract() as ETGVendorPaymentOrderReportContract;
        
        ledgerJournalId = contract.parmLedgerJournalId();

        companyName = CompanyInfo::find().name();

        select count(RecId) from ledgerJournalTransTotal
            where ledgerJournalTransTotal.JournalNum == ledgerJournalId;

        while select ledgerJournalTrans
            where ledgerJournalTrans.JournalNum == ledgerJournalId
        {
            i++;

            tmp.clear();
            tmp.CompanyName = companyName;
            tmp.LineNum = i;
            tmp.TotalLine = ledgerJournalTransTotal.RecId;
            tmp.TransDate = ledgerJournalTrans.TransDate;
            tmp.CurrencyCode = ledgerJournalTrans.CurrencyCode;
            tmp.Amount = ledgerJournalTrans.AmountCurCredit;
            tmp.PaymMode = ledgerJournalTrans.PaymMode;
            tmp.Txt = ledgerJournalTrans.Txt;

            VendAccount vendAccount = LedgerDynamicAccountHelper::getAccountNumberFromDynamicAccount(ledgerJournalTrans.LedgerDimension);

            vendTable = VendTable::find(vendAccount);
            vendBankAccount = VendBankAccount::find(vendTable.AccountNum, vendTable.BankAccount);
            paxBankBranchTable = PaxBankBranchTable::findByRecId(vendBankAccount.PAXBankBranchRecId);

            tmp.TitleIban = strFmt("%1 / %2 / %3", vendTable.name(), vendBankAccount.BankIBAN, vendBankAccount.AccountNum);
            tmp.BankBranch = strFmt("%1 / %2", vendBankAccount.Name, paxBankBranchTable.BranchName);
            tmp.VATNum = vendTable.VATNum;


            bankAccountID = LedgerDynamicAccountHelper::getAccountNumberFromDynamicAccount(ledgerJournalTrans.OffsetLedgerDimension);
            bankAccountTable = BankAccountTable::find(bankAccountID);
            paxBankBranchTable = PaxBankBranchTable::findByRecId(bankAccountTable.PAXBankBranchRecId);

            tmp.Name = strFmt("%1 %2", paxBankBranchTable.BranchName, paxBankBranchTable.BankBranchId);
            tmp.IBAN = bankAccountTable.IBAN;
            tmp.insert();
        }
    }

}
```

```csharp
public class ETGVendorPaymentOrderReportController extends SrsReportRunController
{
    public static ETGVendorPaymentOrderReportController construct()
    {
        return new ETGVendorPaymentOrderReportController();
    }

    public static void main(Args args)
    {
        ETGVendorPaymentOrderReportController  controller;
            
        controller = ETGVendorPaymentOrderReportController::construct();
      
        controller.parmReportName(ssrsReportStr(ETGVendorPaymentOrderReport, Report));
        controller.parmLoadFromSysLastValue(false);
        controller.parmArgs(args);
        controller.parmShowDialog(false);
        controller.parmDialogCaption("Satıcı ödeme toplu talimatı");
        controller.prePromptModifyContract();
        controller.startOperation();
    }

    protected void prePromptModifyContract()
    {
        ETGVendorPaymentOrderReportContract contract;

        LedgerJournalTable ledgerJournalTable;
        LedgerJournalTrans ledgerJournalTrans;
        LedgerJournalId ledgerJournalId;
        
        contract = this.parmReportContract().parmRdpContract() as ETGVendorPaymentOrderReportContract;

        if (this.parmArgs().dataset() == tableNum(LedgerJournalTable))
        {
            ledgerJournalTable = this.parmArgs().record();
            ledgerJournalId = ledgerJournalTable.JournalNum;
        }
        else if (this.parmArgs().dataset() == tableNum(LedgerJournalTrans))
        {
            ledgerJournalTrans = this.parmArgs().record();
            ledgerJournalId = ledgerJournalTrans.JournalNum;
        }

        contract.parmLedgerJournalId(ledgerJournalId);
        //super();
    }

}
```

---

Artık sıra rapor nesnemizi oluşturmaya geldi. Add - New item diyerek Report nesnesini seçip, isim verildikten sonra projemize ekliyoruz.

![Add New Item](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831648590/dd54512c-c64d-484c-b241-47ace04f0508.png align="center")

Şimdi sıra rapor nesnemize bir Data Set eklemeye geldi. **DataSet** düğümü üzerinde sağ tıkladıktan sonra **New Data Set** tıklanır.

![Report DataSet](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831649763/cc916c22-eaba-4e0d-be34-1c78d592e184.png align="center")

DataSet özellikleri ekranından aşağıda ki ayarlamalar yapılır.

![Report DataSet Propery](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831651184/6f62467f-9db1-4d06-ac07-7e30f61d6d7f.png align="center")

Query özelliği üzerinden ilgili Data provider(DP) class’ımız seçilir. Eğer aşağıda ki ekranda ilgili Data provider(DP) class'ını göremiyorsanız projenizi derlemeniz gerekebilir.

![Report DP class](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831653026/470ff1d8-570d-41d2-8696-07604f838a1a.png align="center")

Tüm alanlar işaretlendikten sonra tamam tuşu ile işlem onaylanır. Böylece rapor nesnemiz ilgili veri kaynağına bağlanmış olur.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1689953774397/e89f4413-9389-4f23-8b7f-54623afbff05.png align="center")

---

Şimdi sıra rapor dizaynına geldi. **Designs** düğümüne sağ tıkladıktan sonra **New&gt;Precision Design** dedikten sonra rapor dizayn edebileceğiniz yeni bir ekran açılacaktır. Bu kısmı sizin hayal gücünüze ve ihtiyaçlarınıza bırakıyorum. :)

![Report Design](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831654710/a537b7b6-973e-499b-b7b9-d4f672d64470.png align="center")

---

Son olarak raporumuz için bir menu item nesnesi oluşturmamız ve ilgili ekranlara bağlamamız gerekiyor. Controller class’ımıza bağlayacağımız için bir **MenuItemAction** oluşturuyoruz. Eğer controller class’ına ihtiyacınız yok ise Output menu item oluşturarak direkt rapor nesnenize bağlayabilirsiniz.

![Action Menu Item](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831655945/0caaee8f-95ba-4960-a785-c77c88e34b40.png align="center")

Raporumuz **LedgerJournalTrans** tablosu üzerinden çalışacağı için LedgerJournalTransDaily formuna menu item’ımızı ekledik.

![Ledger Journal Trans Daily Form](https://cdn.hashnode.com/res/hashnode/image/upload/v1677831657341/023dd8bd-8525-4617-a893-af96c3388462.png align="center")

Son olarak raporu çalıştırdığımda aşağıda ki gibi bir ekran açılıyor. Elimde güzel veriler olsaydı daha dolu bir rapor olabilirdi. :)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1764752204948/3b7415a1-85c5-4576-b55b-dead38e35482.png align="center")
