Установка checkbox триггером before insert/before update

Установка checkbox триггером before insert/before update

Здравствуйте. Я недавно совсем познакомился с VIsualforce. Много чего не понятно пока.
Поэтому ищу помощи у знающих.
У меня имеется объект, хранящий в себе информацию о каких-то товарах. На странице же необходимо автоматически выставлять поле есть/нет в наличии (checkbox) триггером before insert/before update в зависимости от значения в поле количество. Как провернуть это колдунство, подскажите пожалуйста.

Страница:

<apex:page controller="ProductController" tabStyle="Product__c" >

<apex:form >
<apex:pageBlock title="Our Products">
<apex:pageBlockSection columns="1">
<apex:pageBlockTable value="{!products}" var="pitem">

<apex:column headerValue="Product">
<apex:outputText value="{!pitem.Name}"/>
</apex:column>

<apex:column headerValue="Price">
<apex:outputText value="{!pitem.Price}$"/>
</apex:column>

<apex:column headerValue="Number of">
<apex:outputText value="{!pitem.Kolvo}"/>
</apex:column>

<apex:column headerValue="Type">
<apex:outputText value="{!pitem.Type}"/>
</apex:column>

<apex:column headerValue="Date">
<apex:outputText value="{!pitem.Date_add}"/>
</apex:column>

<apex:column headerValue="Release Date">
<apex:outputText value="{!pitem.Date_del}"/>
</apex:column>

<apex:column headerValue="Availability">
<apex:inputCheckbox id="box" />
</apex:column>

</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>


<apex:pageBlock id="block1">
<apex:pageBlockSection columns="2" id="section1" >

<apex:pageBlockSection id="section2" columns="1" collapsible="true" title="Add product">
<apex:pageBlockSection columns="1">
<apex:outputLabel value="Enter a description of the product:"/>
<apex:inputText label="Name:" value="{!inputName}"/>
<apex:inputText label="Price:" value="{!inputPrice}"/>
<apex:inputText label="Number of:" value="{!inputNumber}"/>
<apex:inputText label="Type:" value="{!inputType}"/>
<apex:inputText label="Date YYYY M D:" value="{!inputDate}"/>
<apex:inputText label="Release Date YYYY M D:" value="{!inputRelease}"/>
<apex:commandButton action="{!addProduct}" value="Add product"/>
</apex:pageBlockSection>
</apex:pageBlockSection>



<apex:pageBlockSection title="Delete product" id="section3">
<apex:pageBlockSection columns="1">
<apex:outputText value="Enter a name of the product:"/>
<apex:inputText label="Name:" value="{!inputNameDel}"/>
<apex:commandButton action="{!deleteProduct}" value="Delete"/>
</apex:pageBlockSection>
</apex:pageBlockSection>

</apex:pageBlockSection>
<apex:pageBlockSection title="Search" id="section4">
<apex:pageBlockSection columns="1">
<apex:outputText value="Enter a name for search:"/>
<apex:inputText label="Name:" value="{!inputNameSearch}"/>
<apex:commandButton action="{!searchProduct}" value="Search"/>
<apex:outputText value="You need this:"/>
<apex:outputText value="{!productSearch[0].Type} {!productSearch[0].Name}"/>
</apex:pageBlockSection>
</apex:pageBlockSection>

<script> twistSection(document.getElementById('{!$Component.block1.section1.section2}').getElementsByTagName('img')[0]) </script>
<script> twistSection(document.getElementById('{!$Component.block1.section1.section3}').getElementsByTagName('img')[0]) </script>
<script> twistSection(document.getElementById('{!$Component.block1.section4}').getElementsByTagName('img')[0]) </script>
</apex:pageBlock>

</apex:form>
</apex:page>

Контроллер:

public with sharing class ProductController{

public String inputName{get;set;}
public String inputNameDel{get;set;}
public String inputPrice{get;set;}
public String inputNumber{get;set;}
public String inputType{get;set;}
public String inputDate{get;set;}
public String inputRelease{get;set;}
public String inputNameSearch{get;set;}
public Boolean Availb=false;

List<DisplayProducts> products;
List<DisplayProducts> productSearch;

public List<DisplayProducts> getProducts(){
if(products==null){
products=new List<DisplayProducts>();
for(Product__c item : [SELECT Id__c, Name__c, Price__c, Kolvo__c, Type__c, Date_Add__c, Date_Del__c, Availability__c
FROM Product__c ]){
products.add(new DisplayProducts(item));
}
}
return products;
}
public List<DisplayProducts> getProductSearch() {
return ProductSearch;
}


// Action method to handle purchasing process
public void addProduct() {
Product__c[] m1 = new List<Product__c>();
if(integer.valueof(inputNumber)>0){
Availb=true;
}
String[] Date_str=inputDate.split(' ');
String[] DateRelease_str=inputRelease.split(' ');
Product__c m = new Product__c(
Availability__c=Availb,
Date_Add__c=Date.newInstance(integer.valueof(Date_str[0]),integer.valueof(Date_str[1]),integer.valueof(Date_str[2])),
Date_Del__c=Date.newInstance(integer.valueof(DateRelease_str[0]),integer.valueof(DateRelease_str[1]),integer.valueof(DateRelease_str[2])),
Kolvo__c=integer.valueof(inputNumber),
Name__c=inputName,
Price__c=integer.valueof(inputPrice),
Type__c=inputType
);
insert m;
}

public void deleteProduct(){
for(Product__c pr : [SELECT Id__c, Name__c, Price__c, Kolvo__c, Type__c, Date_Add__c, Date_Del__c, Availability__c
FROM Product__c ]){
if(inputNameDel.equals(pr.Name__c)){
delete pr;
}
}
}

public void searchProduct(){
productSearch=new List<DisplayProducts>();
for(Product__c pr : [SELECT Id__c, Name__c, Price__c, Kolvo__c, Type__c, Date_Add__c, Date_Del__c, Availability__c
FROM Product__c ]){
if(inputNameSearch.equals(pr.Name__c)){
productSearch.add(new DisplayProducts(pr));
}
}
}

public class DisplayProducts{

private Product__c merchandise;
public DisplayProducts(Product__c item) {
this.merchandise = item;
}
public String name {
get { return merchandise.Name__c; }
}
public Decimal price{
get { return merchandise.Price__c; }
}
public Decimal kolvo{
get { return merchandise.Kolvo__c; }
}
public String type{
get { return merchandise.Type__c; }
}
public String date_add{
get { return merchandise.Date_Add__c.format(); }
}
public String date_del{
get { return merchandise.Date_Del__c.format(); }
}
public Boolean availability{
get { return merchandise.Availability__c; }
}

}
}

Я прекрасно понимаю, как плохо выглядит мой код) Но пока ничего лучше не получилось)

Тестовое задание
В apex/triggers создаешь триггер с именем name, где name - твое название
туда пишешь

trigger name on Product__c (before insert, before update) {//product__c замени на своё,как и названия остальных объектов

for (Product__c p : Trigger.new) {
if (g.Count__c == 0) {//само условие - если количество товара == 0
p.Availability__c = false;//чекбокс 0
}
else
p.Availability__c = true;//чекбокс 1
}
}

p.s по крайней мере, я делал так
и колдунства тут нет, колдунство начнется к моменту создания тестового класса
По твоему коду - Id__c и Name__c можно было не создавать - они создаются автоматически, а давать объектам "транслитные(Kolvo__c)" названия - нехорошо.

mesandman
Тестовое задание :)

Таки да, тестовое))
К тестовым классам пока не приступал, а уже как-то страшно стало, после комментария)
И спасибо большое, за помощь)

mesandman
if (g.Count__c == 0) {//само условие - если количество товара == 0
p.Availability__c = false;//чекбокс 0
}
else {
p.Availability__c = true;//чекбокс 1
}

Вот для таких ситуаций советую научиться использовать тернарные операции:
p.Availability__c = g.Count__c == 0 ? true : false

А если делать совсем по-Салесфорски то тут лучше сделать Formula Field c типом checkbox, которое будет рассчитываться автоматически.

DikiiSlon
public void deleteProduct(){

for(Product__c pr : [SELECT Id__c, Name__c, Price__c, Kolvo__c, Type__c, Date_Add__c, Date_Del__c, Availability__c FROM Product__c ]){
if(inputNameDel.equals(pr.Name__c)){
delete pr;
}
}
}

Вот за такое в Salesforce расстреливают

Во-первых, FROM Product__c без WHERE - можно влететь в лимиты. Если на орге больше 50000 продуктов, то получишь exception
Во-вторых, почему if(inputNameDel.equals(pr.Name__c)){ не переместить в WHERE запроса?

FROM Product__c WHERE Name__c = :inputNameDel

B третьих, у ВСЕХ объектов в Salesforce по-умолчанию есть поле Name. Зачем делать кастомное Name__c
И напоследок самое страшное - DML операция внутри FOR!!! (DML операция - это "delete pr;")

Всю твою красоту что ты написал выше можно преобразовать в одну строчку:

delete [SELECT Id FROM Product__c WHERE Name__c = :inputNameDel LIMIT 10000];

Если разберешься что эта строчка делает по каждому элементу - поймешь очень многое в SF

Не знаю как там у вас задача тестовая ставится, но вообще вот так массово удалять записи только по имени - это большое зло! На продакшен такое никак нельзя выпускать :))) Вообще во всем мире delete операции под большим запретом - если хотите удалить запись - лучше сделать поле isDeleted (Boolean) и ставить его в TRUE. Естественно во всех запросах после этого надо добавить проверку что isDelete = FALSE чтобы не выбирать такие записи. Но поверьте, бизнес только спасибо скажет

Dmitry Shnyrev
mesandman
if (g.Count__c == 0) {//само условие - если количество товара == 0
p.Availability__c = false;//чекбокс 0
}
else {
p.Availability__c = true;//чекбокс 1
}

Вот для таких ситуаций советую научиться использовать тернарные операции:
p.Availability__c = g.Count__c == 0 ? true : false

А если делать совсем по-Салесфорски то тут лучше сделать Formula Field c типом checkbox, которое будет рассчитываться автоматически.


Вот про тернарную операцию я совсем забыл, спасибо.
А вообще в этом задании по реализации search и delete можно понять, кто что читал и где искал:)

DikiiSlon
public void deleteProduct(){
for(Product__c pr : [SELECT Id__c, Name__c, Price__c, Kolvo__c, Type__c, Date_Add__c, Date_Del__c, Availability__c
FROM Product__c ]){
if(inputNameDel.equals(pr.Name__c)){
delete pr;
}
}
}

Жэстачайшэ расстреливают)

а я вот когда написал

<apex:column headerValue="Availability">

<apex:inputCheckbox value="{!pitem.Availability}"/>
</apex:column>

мне выдало:
Error: Read only property 'ProductController.DisplayProducts.Availability'

Это я где накосячил?

DikiiSlon
Error: Read only property 'ProductController.DisplayProducts.Availability'

может поле Product__c.Availability__c для твоего профайла открыто только на чтение?

Den Brown
DikiiSlon
Error: Read only property 'ProductController.DisplayProducts.Availability'

может поле Product__c.Availability__c для твоего профайла открыто только на чтение?

вроде как все облазил там, везде Visible стоит

посмотри твой профайл, доступ к объекту Product__c и к полю Availability__c. может у тебя только READ?

Den Brown
посмотри твой профайл, доступ к объекту Product__c и к полю Availability__c. может у тебя только READ?

А подскажи пожалуйста, где проверить это? куда залезть?

иди в свои Personal Information и там увидишь какой у тебя профайл, кликай на него , далее Object Settings и выбирай нужный объект и далее смотри поля

DikiiSlon, чтоб проверить, можешь в дев консоли написать:

System.debug(<объект>.<поле>.getDescribe().isUpdateable()); // expected true

Alex Tsitsura
DikiiSlon, чтоб проверить, можешь в дев консоли написать:

System.debug(<объект>.<поле>.getDescribe().isUpdateable()); // expected true

результат - True

DikiiSlon
public Boolean availability{
get { return merchandise.Availability__c; }
}

Добавь сетер.

public Boolean availability{

get { return merchandise.Availability__c; }
set { merchandise.Availability__c = value; }
}

deleted

Alex Tsitsura
Добавь сетер.

ну Alex - "орлиный глаз"

Сработало)
Спасибо за помощь)

А вот еще:
При добавлении или удалении записей, по нажатию кнопки страница обновляется, но без изменений. Запись добавляется (или удаляется) только после того, как я ручками обновлю страницу. Так ведь быть не должно?

DikiiSlon
А вот еще:
При добавлении или удалении записей, по нажатию кнопки страница обновляется, но без изменений. Запись добавляется (или удаляется) только после того, как я ручками обновлю страницу. Так ведь быть не должно?

Где-то уже это спрашивали

Есть у меня еще уж больно глупый вопрос)
В apex workbook, в разделе Lesson 2: Adding Test Methods описаны действия для добавдения тестовых методов, а именно:
1.In the Repository tab, click Classes in the Setup Entity Type section, and then click New.
Так вот: я не могу найти эту вкладку Repository(( Где же она?

И еще:

Для обновления записей в таблице без перезагрузки страницы Dmitry Shnyrev в соседней ветке советовал обернуть ее в

<apex:outputPanel layout="block" id="rerender_me">...</apex:outputPanel>

сделал. Написал еще:

<apex:commandButton action="{!deleteProduct}" value="Delete" reRender="rerender_me"/>

но ничего.
Нужно ли что-то в контроллере еще дописать? Или может commandButton тоже должна находиться внутри

<apex:outputPanel layout="block" id="rerender_me">...</apex:outputPanel>
?

Видимо достал я всех своими вопросами))

DikiiSlon
Видимо достал я всех своими вопросами))

Google все знает.

DikiiSlon
Есть у меня еще уж больно глупый вопрос)
В apex workbook, в разделе Lesson 2: Adding Test Methods описаны действия для добавдения тестовых методов, а именно:
1.In the Repository tab, click Classes in the Setup Entity Type section, and then click New.
Так вот: я не могу найти эту вкладку Repository(( Где же она?

подсказка: @isTest

Interesting information? Help us, post link to social media..