I need to create a new expense card, the input parameters are Amount, Date and Description.
Fields that must be filled in the expense card to create it:
Card keeper is contact
Months Expenses Applications is a custom object
When creating an expense card, if Months Expenses Applications exists by the date entered in the "Date" field, then a new expense card is created from which Months Expenses Applications is taken from the existing one
if, by the date entered in the "date" field, there is no Months Expenses Applications, you need to create Months Expenses Applications and then create an expense map in which Months Expenses Applications will have a new Months Expenses Applications created
I tried to create an expense map with "Amount" "Date" "Description" equal to the input parameters, but I don't know how to specify MonthExpenseApplication__c
public static void createNewExpenseCard(Integer amount, Date createdDate, String description) {
Month_Expense_Application__c MonthApplication = [
SELECT Name, MonthDate__c
FROM Month_Expense_Application__c
WHERE MonthDate__c =: createdDate
];
if (MonthApplication != null) {
ExpenseCard__c exp = new ExpenseCard__c(
Amount__c = amount,
CardDate__c = createdDate,
Description__c = description,
CardKeeper__c = '0034x00001K7kGCAAZ'
);
exp.MonthExpenseApplication__c = [
SELECT MonthExpenseApplication__c
FROM ExpenseCard__c
WHERE MonthExpenseApplication__c =: MonthApplication.Id
].Id;
insert exp;
} else {
Month_Expense_Application__c monthApp = new Month_Expense_Application__c(
Balance__c = 1000,
MonthDate__c = createdDate,
Keeper__c = '0034x00001K7kGCAAZ'
);
ExpenseCard__c exp2 = new ExpenseCard__c(
Amount__c = amount,
CardDate__c = createdDate,
Description__c = description,
CardKeeper__c = '0034x00001K7kGCAAZ'
);
insert exp2;
}
}
This is dangerous:
Month_Expense_Application__c MonthApplication = [
SELECT Name, MonthDate__c
FROM Month_Expense_Application__c
WHERE MonthDate__c =: createdDate
];
If there are zero results it will throw "list has no rows for assignment". Similar if there's more than 1.
Something like this?
Integer amount = 50;
Date createdDate = System.today();
String description = 'Lorem ipsum...';
Month_Expense_Application__c app;
List<Month_Expense_Application__c> applications = [SELECT Id
FROM Month_Expense_Application__c
WHERE MonthDate__c =: createdDate
LIMIT 1];
if(applications.isEmpty()){
app = new Month_Expense_Application__c(
Balance__c = 1000,
MonthDate__c = createdDate,
Keeper__c = '0034x00001K7kGCAAZ'
);
insert app;
} else {
app = applications[0];
}
// one way or another - the monthly allowance exists now. So just use its id in the lookup
ExpenseCard__c exp = new ExpenseCard__c(
Amount__c = amount,
CardDate__c = createdDate,
Description__c = description,
CardKeeper__c = '0034x00001K7kGCAAZ',
Month_Expense_Application__c = app.Id
);
There are more elegant ways to do it, you'd need to read up about upsert and external ids - but it should be good enough.
Related
I keep getting the following error when I write a test class for opportunity line items.
System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: PricebookEntryId (pricebook entry is in a different pricebook than the one assigned to the opportunity): [PricebookEntryId]
Here is my code.
#isTest
public class PreventLineItemDeletionTestClass {
static testmethod void PreventLineItemDeletionTestClass(){
Id pricebookId = Test.getStandardPricebookId();
// insert product
Product2 p = new Product2();
p.Name = ' Test Product ';
p.Description='Test Product Entry For Product';
p.productCode = 'SFDCPanther-123';
p.isActive = true;
insert p;
// insert pricebook entry for the product
PricebookEntry pbEntry = new PricebookEntry(
Pricebook2Id = pricebookId ,
Product2Id = p.Id,
UnitPrice = 100.00,
IsActive = true);
insert pbEntry;
// Create Opportunity
Opportunity opp = new Opportunity();
opp.Name = 'Opp for Test Account New';
opp.CloseDate= System.Today();
opp.StageName='Negotiation';
opp.Pricebook2Id = pricebookId;
insert opp;
system.debug('opp.pricebook2Id!!!!'+opp.pricebook2Id+'pbEntry.Pricebook2Id !!!'+pbEntry.Pricebook2Id);
// Add product and Pricebook to the particular opportunity using OpportunityLineItem
OpportunityLineItem ol = new OpportunityLineItem();
ol.opportunityid = opp.id;
ol.quantity = 4;
ol.TotalPrice = ol.quantity * pbEntry.UnitPrice ;
ol.Product2Id = p.id;
ol.PricebookEntryId = pbEntry.Id;
ol.Fulfillment__c = 2;
insert ol;
}
}
Could someone please let me know what I am doing wrong.
Best,
Mike
I am kind of new to CPQ and have been trying to create a Quote Line Item with no success.
Opportunity OpportunityOne = [SELECT Id, PriceBook2Id FROM Opportunity WHERE
Id='0067F000008qOJzQAM' LIMIT 1];
Quote QuoteOne = [SELECT Id FROM Quote WHERE Name =:'TestQuote' LIMIT 1];
Product2 Product = [SELECT Id FROM Product2 WHERE Id
=: '01t7F0000032Y89QAE' LIMIT 1];
System.debug('Opportunity: '+OpportunityOne);
System.debug('Quote:'+QuoteOne);
System.debug('Product2:'+Product);
QuoteLineItem QuoteLineItemOne = new QuoteLineItem();
QuoteLineItemOne.QuoteId = QuoteOne.Id;
QuoteLineItemOne.Quantity = 100;
QuoteLineItemOne.UnitPrice = 2000;
QuoteLineItemOne.Product2Id = Product.Id;
insert QuoteLineItemOne;
Why does it keep saying price book entry is missing. It is annoying. Insert fails and I see no object requiring a price book entry field.
Please help me with this.
You'll need to roll the apex API version back to version 38 or earlier in order to create quote lines this way (using product2Id field). As you can see in the object reference from version 39 onwards you'll need to populate the pricebookentryId field instead and leave product2Id null. To get the pricebookEntryId you'll just need an extra query eg.
PriceBookEntry pbe = [SELECT id FROM PricebookEntry
WHERE Product2Id =: Product.id AND Pricebook2Id =: OpportunityOne.pricebook2Id LIMIT 1];
Then just set the pricebookentryId field on your quotelineitem instead of product2Id
Been trying to find a proper solution, but have so far been unable to understand or find one properly.
Have the following DB:
I am trying to get the number of clicks in each month.
So i would get something like:
--------------
January - 10
February - 7
March - 22
etc.
This is my code so far:
var MonthlyCount = from c in ClickStatistics
group c.LogDate by new { date = c.LogDate, Id = c.ID }into grp
select new{
Month = grp.Key.date.Month,
Clicks = grp.Key.Id
};
But right now i am just getting this:
Groups items together that have the same c.LogDate.Month. Selects the first item of the group to extract the month as text value (we grouped by month so they should all be equal in that regard) and counts the number of entries in the group.
var ClickStatistics = new List<Clicks>()
{
new Clicks() { ID = 1, LogDate = DateTime.Now.AddMonths(-1)},
new Clicks() { ID = 2, LogDate = DateTime.Now.AddMonths(-1)},
new Clicks() { ID = 3, LogDate = DateTime.Now.AddMonths(0)},
new Clicks() { ID = 4, LogDate = DateTime.Now.AddMonths(0)},
new Clicks() { ID = 5, LogDate = DateTime.Now.AddMonths(1)},
};
var MonthlyCount = from c in ClickStatistics
group c by new { date = c.LogDate.Month } into grp
select new
{
Month = grp.First().LogDate.ToString("MMMM"),
Clicks = grp.Count(),
};
I have a big table with a binary column for picture. I need to show contents of this table in a view and make it searchable. I have tried only selecting a subset of columns that are needed in this. However, the generated SQL always has all the columns of the table in the generated query.
public IQueryable<ApplicantDTO> GetApplicantQueryable()
{
return DataContext.Applicants
.Include(a => a.Nationality)
.Select(x => new ApplicantDTO
{
Id = x.Id,
BirthDate = x.BirthDate,
Gender = x.Gender,
FirstName = x.FirstName,
LastName = x.LastName,
OtherName = x.OtherName,
MobileNo = x.MobileNo,
Age = x.Age,
Nationality = x.Nationality.National,
Admitted = x.admitted,
Completed = x.Completed
})
.Where(a => a.Admitted == false && a.Completed == true)
.OrderBy(a => a.LastName)
.AsNoTracking();
}
But instead of just specifying the above rows, the generated SQL from profiler is
SELECT
[a].[Id], [a].[BirthDate], [a].[BirthPlace], [a].[CompleteDate],
[a].[Completed], [a].[ContentType], [a].[CreateDate],
[a].[Denomination], [a].[Disability], [a].[Email],
[a].[FirstName], [a].[Gender], [a].[HomeTown], [a].[LastName],
[a].[MarryStatus], [a].[MatureApp], [a].[MobileNo], [a].[NationalityID],
[a].[OtherName], [a].[Passport], [a].[Pin], [a].[PostalAddress],
[a].[Region], [a].[Religion], [a].[ResAddress], [a].[SerialNo],
[a].[Title], [a].[VoucherID], [a].[admitted], [a.Nationality].[National]
FROM
[Applicants] AS [a]
INNER JOIN
[Nationality] AS [a.Nationality] ON [a].[NationalityID] = [a.Nationality].[Id]
WHERE
([a].[admitted] = 0)
AND ([a].[Completed] = 1)
ORDER BY
[a].[LastName]
With all the underlying columns all included in the query.
I tried putting it in an anonymous type before casting it to the ApplicantDTO but still the same effect.
What's wrong?
my current query is:
public function teachers_manage() {
$this->db->select('users.user_id, teacher_id, COUNT(student_id) AS S, COUNT(DISTINCT(users.class)) AS C, schools.region, schools.school_name');
$this->db->from('teacher_student_conn');
$this->db->join('users', 'teacher_student_conn.student_id=users.user_id','left');
$this->db->join('schools', 'schools.school_id=users.school_id');
$this->db->where('users.deactivated_at = "0000-00-00 00:00:00" OR users.deactivated_at IS NULL ');
$this->db->where('users.role_id', '1');
$this->db->group_by("teacher_student_conn.teacher_id");
$result=$this->db->get();
return $result->result();
}
It shows me teachers and for each teacher number of classes he teaches and number of students he teaches. I have made join 2 tables - users and teacher_student_conn by users=user_id=teacher_student_conn.student_id and I've put where clause for student not to be deactivated - shows active students. But how to do that also fot the teachers? Another join will change the results. I only want to add where clause for teachers to be active.
My tables look like this:
users
user_id
school_id
class
role_id
created_at
deactivated_at
teacher-student_conn
id
teacher_id
student_id
created_at
I suggest to add a column for "status" to more easily distinguish the status of student and teacher.
And this is my recommended query
SQL Query:
select
from users a
join teacher-student_conn b on a.user_id = b.student_id
join schools c on c.school_id = a.school_id
where (a.status = "Deactivated") and (b.status = "Deactivated")
For codeigniter:
$this->db->select('a.user_id, b.teacher_id, COUNT(b.student_id) AS S, COUNT(DISTINCT(a.class)) AS C, c.region, c.school_name');
$this->db->join('teacher_student_conn b', 'b.student_id = a.user_id','left');
$this->db->join('schools c', 'c.school_id = a.school_id');
$this->db->where('a.status = "Deactivated" or b.status = "Deactivated" ');
$this->db->where('a.role_id', '1');
$this->db->group_by("b.teacher_id");
$result=$this->db->get("users a");
return $result->result();