How to add new ticket summary in orchard? - orchardcms

I have create a ticket dashboard and it will shows two ticket summaries after I login with my administrator account. One is "Your ticket summary" and the other "All ticket summary". Right now I'm planning to let my administrator account to see other account's ticket summary (like this), but I don't know how to add it on to the ticket dashboard can somebody show me how to do it?

I guess you asked the question as a comment in the previous post too! but anyway,
there are several approaches to do so. Orchard Collaboration uses a widget to represents Ticket Summaries (both for the user and for the admin). The main logic is in the DashboardDriver at Modules/Orchard.CRM.Core/Drivers.
private DriverResult DisplayDetail(DashboardPart part, dynamic shapeHelper)
{
if (this.services.WorkContext.CurrentUser == null)
{
return null;
}
var contentQuery = this.services.ContentManager.HqlQuery().ForVersion(VersionOptions.Published);
var statusRecords = this.basicDataService.GetStatusRecords().OrderBy(c => c.OrderId).ToList();
DashboardViewModel model = new DashboardViewModel();
model.CurrentUserId = this.services.WorkContext.CurrentUser.Id;
model.IsCustomer = this.crmContentOwnershipService.IsCurrentUserCustomer();
model.IsOperator = this.services.Authorizer.Authorize(Permissions.OperatorPermission);
dynamic state = new JObject();
// Query items created by customer
if (model.IsCustomer)
{
// Ticket contentType
state.ContentTypes = "Ticket";
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, "Content", "ContentTypes", state);
state.RequestingUser_Id = model.CurrentUserId.ToString(CultureInfo.InvariantCulture);
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, TicketFieldsFilter.CategoryName, TicketFieldsFilter.RequestingUserType, state);
var userTicketsCountByStateIds = groupQuery.GetCount(contentQuery, "TicketPartRecord", "StatusRecord.Id");
model.CurrentUserRequestingTickets = new Collection<dynamic>();
CRMHelper.AddStatusGroupRecordsToModel(statusRecords, userTicketsCountByStateIds, model.CurrentUserRequestingTickets);
// overrude items of current users
state.MaxDueDate = DateTime.UtcNow.Date;
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, TicketFieldsFilter.CategoryName, TicketFieldsFilter.TicketDueDateType, state);
model.CurrentUserOverrudeRequestingTicketCount = contentQuery.Count();
}
// Query the counts of the current user tickets group by stateId
// *******************************************************
if (model.IsOperator)
{
// Ticket contentType
state.ContentTypes = "Ticket";
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, "Content", "ContentTypes", state);
dynamic temp = new
{
Users = new int[] { model.CurrentUserId },
Teams = new int[] { },
BusinessUnits = new int[] { },
AccessType = ContentItemPermissionAccessTypes.Assignee
};
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, ContentItemPermissionFilter.CategoryName, ContentItemPermissionFilter.AnySelectedUserTeamBusinessUnit, temp);
var userTicketsCountByStateIds = groupQuery.GetCount(contentQuery, "TicketPartRecord", "StatusRecord.Id");
model.CurrentUserTickets = new Collection<dynamic>();
CRMHelper.AddStatusGroupRecordsToModel(statusRecords, userTicketsCountByStateIds, model.CurrentUserTickets);
// overrude items of current users
state.MaxDueDate = DateTime.UtcNow.Date;
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, TicketFieldsFilter.CategoryName, TicketFieldsFilter.TicketDueDateType, state);
model.CurrentUserOverrudeItemsCount = contentQuery.Count();
//*******************************************************
}
bool isAdmin = this.services.Authorizer.Authorize(Permissions.AdvancedOperatorPermission);
if (isAdmin)
{
// Query the counts of the whole tickets in the system based on stateId
state = new JObject();
contentQuery = this.services.ContentManager.HqlQuery().ForVersion(VersionOptions.Published);
state.ContentTypes = "Ticket";
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, "Content", "ContentTypes", state);
var ticketCountsByStateIds = groupQuery.GetCount(contentQuery, "TicketPartRecord", "StatusRecord.Id");
model.AllTickets = new Collection<dynamic>();
CRMHelper.AddStatusGroupRecordsToModel(statusRecords, ticketCountsByStateIds, model.AllTickets);
state.MaxDueDate = DateTime.UtcNow.Date;
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, TicketFieldsFilter.CategoryName, TicketFieldsFilter.TicketDueDateType, state);
model.AllOverrudeItemsCount = contentQuery.Count();
}
// get items without any owner
contentQuery = this.services.ContentManager.HqlQuery().ForVersion(VersionOptions.Published);
state.ContentTypes = "Ticket";
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, "Content", "ContentTypes", state);
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, ContentItemPermissionFilter.CategoryName, "ContentItemPermissionPartRecord.ItemsWithoutAnyOwner", state);
model.AllItemsWithoutOwnerCount = contentQuery.Count();
// get overrude items count
// display
// 1) Number of your open, new, in progress, and closed tickets
// 2) number of the unassigned, new, open, in progress and closed tickets in the system.
return ContentShape("Parts_Dashboard",
() => shapeHelper.Parts_Dashboard(
Model: model
));
}
You need to create a new Widget similar to that one. DashboardDriver represents tickets of the logined user as well as summary of all tickets. In the new widget, you can only represents summary tickets of the user. The new widget must have a UserId property and represents ticket summary of that user instead of the logined user. Something like this:
private DriverResult DisplayDetail(NewUserDashboardPart part, dynamic shapeHelper)
{
if (this.services.WorkContext.CurrentUser == null)
{
return null;
}
var contentQuery = this.services.ContentManager.HqlQuery().ForVersion(VersionOptions.Published);
var statusRecords = this.basicDataService.GetStatusRecords().OrderBy(c => c.OrderId).ToList();
DashboardViewModel model = new DashboardViewModel();
model.CurrentUserId = NewUserDashboardPart.UserId;
dynamic state = new JObject();
// Query the counts of the current user tickets group by stateId
// *******************************************************
// Ticket contentType
state.ContentTypes = "Ticket";
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, "Content", "ContentTypes", state);
dynamic temp = new
{
Users = new int[] { model.CurrentUserId },
Teams = new int[] { },
BusinessUnits = new int[] { },
AccessType = ContentItemPermissionAccessTypes.Assignee
};
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, ContentItemPermissionFilter.CategoryName, ContentItemPermissionFilter.AnySelectedUserTeamBusinessUnit, temp);
var userTicketsCountByStateIds = groupQuery.GetCount(contentQuery, "TicketPartRecord", "StatusRecord.Id");
model.CurrentUserTickets = new Collection<dynamic>();
CRMHelper.AddStatusGroupRecordsToModel(statusRecords, userTicketsCountByStateIds, model.CurrentUserTickets);
// overrude items of current users
state.MaxDueDate = DateTime.UtcNow.Date;
contentQuery = this.projectionManagerWithDynamicSort.ApplyFilter(contentQuery, TicketFieldsFilter.CategoryName, TicketFieldsFilter.TicketDueDateType, state);
model.CurrentUserOverrudeItemsCount = contentQuery.Count();
//*******************************************************
// display
// 1) Number of your open, new, in progress, and closed tickets
// 2) number of the unassigned, new, open, in progress and closed tickets in the system.
return ContentShape("Parts_Dashboard",
() => shapeHelper.Parts_Dashboard(
Model: model
));
}

Related

Acumatica API Error when creating a Inventory Receipts API calls

Good day
I am creating a SOAP contract base connection to Acumatica.
I am getting an error: "System.ArgumentNullException: Value cannot be null."
I am not sure why I am getting the error.
Here is my code
using (var soapClient = new DefaultSoapClient())
{
try
{
soapClient.Login();
InventoryReceipt NewinventoryReceipt = new InventoryReceipt
{
ReferenceNbr = new StringValue { Value = "<NEW>" },
Hold = new BooleanValue { Value = true },
Date = new DateTimeValue { Value = DateTime.Now },
PostPeriod = new StringValue { Value = DateTime.Now.ToString("DD-yyyy") },
TransferNbr = new StringValue { Value = "" },
//External Ref
Description = new StringValue { Value = "" },
Details = new InventoryReceiptDetail[]
{
new InventoryReceiptDetail
{
//branch
InventoryID = new StringValue{Value = "NIS777"},
WarehouseID = new StringValue{Value = "FBTZEST"},
Location = new StringValue {Value = "BULK"},
Qty = new DecimalValue{Value = 1},
UOM = new StringValue{Value = "PALLET"},
UnitCost = new DecimalValue{Value = 91},
ExtCost = new DecimalValue{Value = 91},
LotSerialNbr = new StringValue{Value = "PLN12345"},
ExpirationDate = new DateTimeValue{Value = DateTime.Now},
// ReasonCode
Description = new StringValue{Value = ""}
}
},
};
InventoryReceipt putInventoryReceipt = (InventoryReceipt)soapClient.Put(NewinventoryReceipt);
}
catch (Exception ex)
{
soapClient.Logout();
throw;
}
finally
{
soapClient.Logout();
}
soapClient.Logout();
}
Console.ReadLine();
}
Is there any way to see what is null or what I am missing to post this data?
Have you tried manually entering the data into the UI? The Validation on the web service should be the same as the UI, so you might get more info from the UI. You have a lot of dependent values here since you're referencing a specific Lot perhaps a value is missing. Other than that, you might try adding Project = X.

Closing Case in Acumatica through API

I want to close the case in Partners Portal remotely using Web API, whenever I close the case in my (client) side. I was able to implement the code but ran into below issue.
It is changing the status and resolution of the case in Partners Portal but Close Case button is enabled and it is visible in My Open Case bucket. Please let me know if I can close the case remotely using Web API or if I am missing anything.
protected virtual void CRCase_RowPersisting(PXCache cache, PXRowPersistingEventArgs e)
{
var caseRow = (CRCase)e.Row;
if (caseRow != null)
{
if (caseRow.Status == "C") // Closed
{
string cloud9CaseCD = null;
cloud9CaseCD = CRCaseForCreate.Current.CaseCD;
string acumaticaCaseCD = string.Empty;
CSAnswers aCCaseNoAttribute = PXSelect<CSAnswers,
Where<CSAnswers.refNoteID, Equal<Required<CSAnswers.refNoteID>>,
And<CSAnswers.attributeID, Equal<Required<CSAnswers.attributeID>>>>>.Select(new PXGraph(), CRCaseForCreate.Current.NoteID, "ACCASENO");
if (aCCaseNoAttribute != null)
{
acumaticaCaseCD = aCCaseNoAttribute.Value;
if(!string.IsNullOrEmpty(acumaticaCaseCD))
{
SP203000WS.Screen context = new SP203000WS.Screen();
context.CookieContainer = new System.Net.CookieContainer();
context.AllowAutoRedirect = true;
context.EnableDecompression = true;
context.Timeout = 1000000;
context.Url = "https://sso.acumatica.com/Soap/SP203000.asmx";
PartnerPortalCreds loginCreds = GetCreds();
string username = loginCreds.PARTPRTUSE;
string password = loginCreds.PARTPRTPAS;
SP203000WS.LoginResult result = context.Login(username, password);
SP203000WS.Content CR306000 = context.GetSchema();
context.Clear();
SP203000WS.Content[] CR306000Content = context.Submit
(
new SP203000WS.Command[]
{
new SP203000WS.Value
{
Value = acumaticaCaseCD,
LinkedCommand = CR306000.Case.CaseID
},
new SP203000WS.Value
{
Value = "C",
LinkedCommand = new SP203000WS.Field { FieldName="Status", ObjectName="Case"}
},
new SP203000WS.Value
{
Value = "RD",
LinkedCommand = new SP203000WS.Field { FieldName="Resolution", ObjectName="Case"}
},
CR306000.Actions.Submit,
CR306000.Case.CaseID
}
);
context.Logout();
}
}
}
}
}
Tried below code using CloseCase Action: -
protected virtual void CRCase_RowPersisting(PXCache cache, PXRowPersistingEventArgs e)
{
var caseRow = (CRCase)e.Row;
if (caseRow != null)
{
if (caseRow.Status == "C") // Closed
{
string cloud9CaseCD = null;
cloud9CaseCD = CRCaseForCreate.Current.CaseCD;
string acumaticaCaseCD = string.Empty;
CSAnswers aCCaseNoAttribute = PXSelect<CSAnswers,
Where<CSAnswers.refNoteID, Equal<Required<CSAnswers.refNoteID>>,
And<CSAnswers.attributeID, Equal<Required<CSAnswers.attributeID>>>>>.Select(new PXGraph(), CRCaseForCreate.Current.NoteID, "ACCASENO");
if (aCCaseNoAttribute != null)
{
acumaticaCaseCD = aCCaseNoAttribute.Value;
if (!string.IsNullOrEmpty(acumaticaCaseCD))
{
SP203010WS.Screen context = new SP203010WS.Screen();
context.CookieContainer = new System.Net.CookieContainer();
context.AllowAutoRedirect = true;
context.EnableDecompression = true;
context.Timeout = 1000000;
context.Url = "https://sso.acumatica.com/Soap/SP203010.asmx";
PartnerPortalCreds loginCreds = GetCreds();
string username = loginCreds.PARTPRTUSE;
string password = loginCreds.PARTPRTPAS;
SP203010WS.LoginResult result = context.Login(username, password);
SP203010WS.Content CR306000 = context.GetSchema();
context.Clear();
var commands1 = new SP203010WS.Command[]
{
new SP203010WS.Value
{
Value = acumaticaCaseCD,
LinkedCommand = CR306000.Case.CaseID
},
new SP203010WS.Value
{
Value = "Yes",
LinkedCommand = CR306000.Case.ServiceCommands.DialogAnswer, Commit = true
},
CR306000.Actions.CloseCase
};
var data = context.Submit(commands1);
context.Logout();
}
}
}
}
}
In the below image you can see that the case is already closed but Close Case menu button is still visible.
Close Case Confirmation Dialogbox on Partners Portal. How should I answer this dialogbox programatically while closing the case using Web API.
Have you tried to invoke Close action via Web API instead of changing values of the Status and Resolution fields? As far as I know, Close button on the Partner Portal updates support case Status to Open and Reason to Pending Closure. Then it's up to support personnel to manually close the case.
Finally found the solution. Updated the code for CloseCase (second code snippet). This will mark the case as Pending Closure in Partners Portal.

Add Join in BQLCommand

I would like to join the following statement with EPEmployee table on EPEmployee's BAccountID with FSAppointmentEmployee's EmployeeID column then put where condition on EPEmployee's UserID with currently logged in employee's user id in the current BQLCommand for PXAdapter, so that I can see the list of appointments that are assigned to current employee only.
public static PXAdapter PrepareCustomNavAdapter(PXAction action, PXAdapter adapter, bool prevNextAction = false)
{
var select = adapter.View.BqlSelect;
select = select
.WhereAnd<Where<EPEmployee.userID,Equal<AccessInfo.userID>>>()
.OrderByNew<OrderBy<
Desc<FSAppointment.createdDateTime,
Desc<FSAppointment.srvOrdType,
Desc<FSAppointment.refNbr>>>>>();
var newAdapter = new PXAdapter(new PXView(action.Graph, true, select))
{
MaximumRows = adapter.MaximumRows
};
object current = action.Graph.Views[action.Graph.PrimaryView].Cache.Current;
if (prevNextAction)
{
var sortColumns = new string[adapter.SortColumns.Count() + 1];
adapter.SortColumns.CopyTo(sortColumns, 1);
sortColumns[0] = "CreatedDateTime";
newAdapter.SortColumns = sortColumns;
var descendings = new bool[adapter.Descendings.Count() + 1];
adapter.Descendings.CopyTo(descendings, 1);
descendings[0] = true;
newAdapter.Descendings = descendings;
var searches = new object[adapter.Searches.Count() + 1];
adapter.Searches.CopyTo(searches, 1);
if (current != null && current is FSAppointment)
searches[0] = ((FSAppointment)current).CreatedDateTime;
newAdapter.Searches = searches;
}
else if (current != null)
{
adapter.Currents = new object[] { current };
}
return newAdapter;
}
So that, only these two employees would be able to see that appointment.
Thank you.
AccessInfo is a Singleton, you should decorate it with Current class:
Where<EPEmployee.userID, Equal<Current<AccessInfo.userID>>>

NetSuite SuiteTalk API - Get Inventory Details

I'm using the SuiteTalk (API) service for NetSuite to retrieve a list of Assemblies. I need to load the InventoryDetails fields on the results to view the serial/lot numbers assigned to the items. This is the current code that I'm using, but the results still show those fields to come back as NULL, although I can see the other fields for the AssemblyBuild object. How do I get the inventory details (serials/lot#'s) to return on a transaction search?
public static List<AssemblyBuildResult> Get()
{
var listAssemblyBuilds = new List<AssemblyBuildResult>();
var service = Service.Context();
var ts = new TransactionSearch();
var tsb = new TransactionSearchBasic();
var sfType = new SearchEnumMultiSelectField
{
#operator = SearchEnumMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new string[] { "_assemblyBuild" }
};
tsb.type = sfType;
ts.basic = tsb;
ts.inventoryDetailJoin = new InventoryDetailSearchBasic();
// perform the search
var response = service.search(ts);
response.pageSizeSpecified = true;
// Process response
if (response.status.isSuccess)
{
// Process the records returned in the response
// Get more records with pagination
if (response.totalRecords > 0)
{
for (var x = 1; x <= response.totalPages; x++)
{
var records = response.recordList;
foreach (var t in records)
{
var ab = (AssemblyBuild) t;
listAssemblyBuilds.Add(GetAssemblyBuildsResult(ab));
}
if (response.pageIndex < response.totalPages)
{
response = service.searchMoreWithId(response.searchId, x + 1);
}
}
}
}
// Parse and return NetSuite WorkOrder into assembly WorkOrderResult list
return listAssemblyBuilds;
}
After much pain and suffering, I was able to solve this problem with the following code:
/// <summary>
/// Returns List of AssemblyBuilds from NetSuite
/// </summary>
/// <returns></returns>
public static List<AssemblyBuildResult> Get(string id = "", bool getDetails = false)
{
// Object to populate and return results
var listAssemblyBuilds = new List<AssemblyBuildResult>();
// Initiate Service and SavedSearch (TransactionSearchAdvanced)
var service = Service.Context();
var tsa = new TransactionSearchAdvanced
{
savedSearchScriptId = "customsearch_web_assemblysearchmainlist"
};
// Filter by ID if specified
if (id != "")
{
tsa.criteria = new TransactionSearch()
{
basic = new TransactionSearchBasic()
{
internalId = new SearchMultiSelectField
{
#operator = SearchMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new[] {
new RecordRef() {
type = RecordType.assemblyBuild,
typeSpecified = true,
internalId = id
}
}
}
}
};
}
// Construct custom columns to return
var tsr = new TransactionSearchRow();
var tsrb = new TransactionSearchRowBasic();
var orderIdCols = new SearchColumnSelectField[1];
var orderIdCol = new SearchColumnSelectField();
orderIdCols[0] = orderIdCol;
tsrb.internalId = orderIdCols;
var tranDateCols = new SearchColumnDateField[1];
var tranDateCol = new SearchColumnDateField();
tranDateCols[0] = tranDateCol;
tsrb.tranDate = tranDateCols;
var serialNumberCols = new SearchColumnStringField[1];
var serialNumberCol = new SearchColumnStringField();
serialNumberCols[0] = serialNumberCol;
tsrb.serialNumbers = serialNumberCols;
// Perform the Search
tsr.basic = tsrb;
tsa.columns = tsr;
var response = service.search(tsa);
// Process response
if (response.status.isSuccess)
{
var searchRows = response.searchRowList;
if (searchRows != null && searchRows.Length >= 1)
{
foreach (SearchRow t in searchRows)
{
var transactionRow = (TransactionSearchRow)t;
listAssemblyBuilds.Add(GetAssemblyBuildsResult(transactionRow, getDetails));
}
}
}
// Parse and return NetSuite WorkOrder into assembly WorkOrderResult list
return listAssemblyBuilds;
}
private static string GetAssemblyBuildLotNumbers(string id)
{
var service = Service.Context();
var serialNumbers = "";
var tsa = new TransactionSearchAdvanced
{
savedSearchScriptId = "customsearch_web_assemblysearchlineitems"
};
service.searchPreferences = new SearchPreferences { bodyFieldsOnly = false };
tsa.criteria = new TransactionSearch()
{
basic = new TransactionSearchBasic()
{
internalId = new SearchMultiSelectField
{
#operator = SearchMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new[] {
new RecordRef() {
type = RecordType.assemblyBuild,
typeSpecified = true,
internalId = id
}
}
}
}
};
// Construct custom columns to return
var tsr = new TransactionSearchRow();
var tsrb = new TransactionSearchRowBasic();
var orderIdCols = new SearchColumnSelectField[1];
var orderIdCol = new SearchColumnSelectField();
orderIdCols[0] = orderIdCol;
tsrb.internalId = orderIdCols;
var serialNumberCols = new SearchColumnStringField[1];
var serialNumberCol = new SearchColumnStringField();
serialNumberCols[0] = serialNumberCol;
tsrb.serialNumbers = serialNumberCols;
tsr.basic = tsrb;
tsa.columns = tsr;
var response = service.search(tsa);
if (response.status.isSuccess)
{
var searchRows = response.searchRowList;
if (searchRows != null && searchRows.Length >= 1)
{
foreach (SearchRow t in searchRows)
{
var transactionRow = (TransactionSearchRow)t;
if (transactionRow.basic.serialNumbers != null)
{
return transactionRow.basic.serialNumbers[0].searchValue;
}
}
}
}
return serialNumbers;
}
private static AssemblyBuildResult GetAssemblyBuildsResult(TransactionSearchRow tsr, bool getDetails)
{
if (tsr != null)
{
var assemblyInfo = new AssemblyBuildResult
{
NetSuiteId = tsr.basic.internalId[0].searchValue.internalId,
ManufacturedDate = tsr.basic.tranDate[0].searchValue,
SerialNumbers = tsr.basic.serialNumbers[0].searchValue
};
// If selected, this will do additional NetSuite queries to get detailed data (slower)
if (getDetails)
{
// Look up Lot Number
assemblyInfo.LotNumber = GetAssemblyBuildLotNumbers(tsr.basic.internalId[0].searchValue.internalId);
}
return assemblyInfo;
}
return null;
}
What I learned about pulling data from NetSuite:
Using SavedSearches is the best method to pull data that doesn't automatically come through in the API objects
It is barely supported
Don't specify an ID on the SavedSearch, specify a criteria in the TransactionSearch to get one record
You will need to specify which columns to actually pull down. NetSuite doesn't just send you the data from a SavedSearch automatically
You cannot view data in a SavedSearch that contains a Grouping
In the Saved Search, use the Criteria Main Line = true/false to read data from the main record (top of UI screen), and line items (bottom of screen)

How to Mock Subsonic ExecuteReader method?

I have a method that calls stored procedure and returns the data after executing DataReader.
I am trying to test the method using mock. I am not sure how to return value?
Anyone did this? Appreciate your responses.
Here is my code:
// Call the StoredProcedure
public List<string> GetCompletedBatchList(int fileId)
{
List<string> completedBatches = new List<string>();
StoredProcedure sp = new StoredProcedure("GetDistributedBatches", this.dataProvider);
sp.Command.AddParameter("FileID", fileId, DbType.Int32, ParameterDirection.Input);
sp.Command.AddParameter("Result", null, DbType.Int32, ParameterDirection.InputOutput);
using (var rdr = sp.ExecuteReader())
{
while (rdr != null && rdr.Read())
{
if (rdr[0] != null)
{
completedBatches.Add(rdr[0].ToString());
}
}
}
return completedBatches;
}
Here is the Test Method:
[Test]
public void Can_get_completedBatches()
{
var file = new File() { FileID = 1, DepositDate = DateTime.Now };
repo.Add<File>(file);
CompletedBatches completedBatches = new CompletedBatches(provider.Object);
//Here I am not sure how to Return
provider.Setup(**x => x.ExecuteReader(It.IsAny<QueryCommand>())).Returns** =>
{
cmd.OutputValues.Add(0);
});
var completedBatchesList = completedBatches.GetCompletedBatchList(file.FileID);
Assert.AreEqual(0, completedBatchesList.Count());
}
If you want to create a DataReader of a certain shape and size then I suggest you look at DataTable.CreateDataReader DataTable.CreateDataReader. You can then setup the ExecuteReader in your example to return this datareader.
The following link helped me...
How to mock an SqlDataReader using Moq - Update
I used MockDbDataReader method to mock the data
[Test]
public void Can_get_completedBatches_return_single_batch()
{
var date = DateTime.Now;
var file = new File() { FileID = 202, DepositDate = DateTime.Now };
var batch1 = new Batch() { FileID = 202, BatchID = 1767, LockboxNumber = "1", IsLocked = true, LockedBy = "testUser" };
var transaction1 = new Transaction() { BatchID = 1767, TransactionID = 63423, CheckAmount = 100.0 };
var distribution1 = new Distribution() { TransactionID = 63423, InvoiceNumber = "001", Amount = 100.0, DateCreated = date, DateModified = date, TransType = 2 };
repo.Add<File>(file);
repo.Add<Batch>(batch1);
repo.Add<Transaction>(transaction1);
repo.Add<Distribution>(distribution1);
CompletedBatches completedBatches = new CompletedBatches(provider.Object);
provider.Setup(x => x.ExecuteReader(It.IsAny<QueryCommand>())).Returns(MockDbDataReader());
var completedBatchesList = completedBatches.GetCompletedBatchList(202);
Assert.AreEqual(1, completedBatchesList.Count());
}
// You should pass here a list of test items, their data
// will be returned by IDataReader
private DbDataReader MockDbDataReader(List<TestData> ojectsToEmulate)
{
var moq = new Mock<DbDataReader>();
// This var stores current position in 'ojectsToEmulate' list
int count = -1;
moq.Setup(x => x.Read())
// Return 'True' while list still has an item
.Returns(() => count < ojectsToEmulate.Count - 1)
// Go to next position
.Callback(() => count++);
moq.Setup(x => x["BatchID"])
// Again, use lazy initialization via lambda expression
.Returns(() => ojectsToEmulate[count].ValidChar);
return moq.Object;
}

Resources